虚拟函数在C ++中是否只能覆盖?

时间:2012-02-02 22:13:31

标签: c# c++ inheritance polymorphism

在C#中,基类的虚方法可以被其派生类覆盖或隐藏,例如

using System;

class A {
 public virtual void M() {
  System.Console.WriteLine("A");
 }
}

class B: A {
 public override void M() {
  System.Console.WriteLine("B");
 }
}

class C: A {
 public new void M() {
  System.Console.WriteLine("C");
 }
}

class P {
 static void Main(string[] args) {
  A b = new B();
  b.M();
  A a = new C();
  a.M();
 }
}

输出:

B
A

在C ++中怎么样?只能覆盖?

4 个答案:

答案 0 :(得分:5)

[C ++ 11更新]

从C ++ 11开始,您可以使用override关键字告诉编译器您打算覆盖基类虚函数。

void foo() override;

如果没有override关键字但基类包含具有相同*签名的虚函数,则该函数仍会被覆盖。否则,隐藏。

[C ++ 03的原始答案]

当然,你可以在C ++中覆盖和隐藏虚函数。你对此并不是很明确(不管怎么说都不是在C ++ 03中)。

例如

class A
{
public:
   virtual int f(char);
};

class B : public A
{
public:
    virtual int f(); //hides A::f
};

class C : public A
{
public:
    virtual int f(char); //overrides A::f
};

如果签名与Base虚方法*一致,那么它就会覆盖。否则它就藏起来了。

所以有时候你不小心忘了const并最终隐藏了这个函数而不是覆盖它。调用C ++ 11覆盖属性来解决此问题。如果使用此覆盖属性但签名不兼容,则会出现编译器错误。

*(或不同之处仅在于返回类型分别是对Base类和公共派生类的指针或引用)

答案 1 :(得分:2)

在C ++中,派生类中具有相同签名(返回类型,参数和CV / ref限定符)的成员函数作为基类中同名的虚函数会覆盖该函数;如果签名不同或基类功能不是虚拟的,则隐藏基类功能。 (虽然这个涉及协变返回类型的规则略有修改。)

在C ++ 11中,您可以使用override关键字显式请求派生类中的成员函数是覆盖,并且您可以请求不能覆盖基类函数(使用{{ 1}}关键字),如果您尝试意外覆盖或隐藏,会导致编译时错误。

答案 2 :(得分:2)

在C ++中,具有相同名称并使用相同参数(包括this参数的cv限定条件)的派生类中的函数作为在直接或间接基类中声明为虚拟的函数始终会覆盖基类功能。

重写函数必须具有相同的返回类型(或协变返回类型),否则覆盖函数的声明无效。

如果函数参数不匹配任何具有相同名称的基类函数(虚拟或非虚函数)被派生类的函数定义隐藏。

(从技术上讲,重写函数也隐藏了它覆盖的基类函数,但这纯粹是学术观点。)

答案 3 :(得分:0)

在这里,您的代码中发生了什么: 当你在编译时写b.M()时,它会被要求B级“嘿B级,你有方法M”B说是的我有。在哪儿?在我的基类A中。

然后在运行时:“B你覆盖方法M”,B:“是的我做”... INVOKE覆盖

当您在编译时询问C时,您是否有一个名为M的方法,它说“是,在基类A中”在运行时,您覆盖M,C表示“否”,OK在基类中调用M < / p>