虚拟函数只能在C++中重写吗

本文关键字:重写 C++ 函数 虚拟 | 更新日期: 2023-09-27 18:22:13

在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++怎么样?只能重写?

虚拟函数只能在C++中重写吗

[为C++11更新]

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

void foo() override;

如果没有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覆盖属性就是为了解决这个问题。如果使用此重写属性,但签名不兼容,则会出现编译器错误。

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

在C++中,派生类中与基类中同名虚拟函数具有相同签名(返回类型、参数和CV/ref限定符)的成员函数会覆盖该函数;如果签名不同或者基类函数不是虚拟的,那么基类函数是隐藏的。(尽管这个规则有一个轻微的修改,涉及协变返回类型。)

在C++11中,您可以使用override关键字显式请求重写派生类中的成员函数,也可以请求不能重写基类函数(使用final关键字),如果您试图意外重写或隐藏,则会导致编译时错误。

在C++中,派生类中与直接或间接基类中声明为虚拟的函数具有相同名称并采用相同参数(包括this参数的cv限定)的函数总是覆盖基类函数。

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

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

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

这里,您的代码中发生了什么:当你在编译时写b.M()时,它被问到类b"嘿,类b,你有方法吗?"b说是的,我有。它在哪里?在我的A级基础课上。

然后在运行时:"B你覆盖方法M吗",B:"是的,我覆盖"。。。INVOKE覆盖

当你在编译时问C你有一个名为M的方法时,它会说"是的,在基类a中"。在运行时,你是否覆盖M,C会说"否",好的,在你的基类中调用M