13

我知道 C++ 通过虚函数实现了运行时多态性,并且 virtual 关键字是继承的,但我没有看到在派生类中使用 virtual 关键字。

例如,在以下情况下,即使您在派生类中删除了虚拟关键字,ptr->method() 调用仍会转到派生::method。那么这个 virtual 关键字在派生类中做了什么额外的事情呢?

#include<iostream>

using namespace std;

class base
{
public:
    virtual void method()
    {
        std::cout << std::endl << "BASE" << std::endl;
    }
};

class derived: public base
{
public:
    virtual void method()
    {
        std::cout << std::endl << "DERIVED" << std::endl;
    }
};

int main()
{
    base* ptr = new derived();
    ptr->method();
    return 9;
}
4

5 回答 5

22

如果派生类的方法通过名称和签名与基类之一的虚拟方法匹配,并且匹配的方法是虚拟的,那么派生类的方法也变为虚拟的。因此,从技术上讲,没有必要在派生类中将此类方法标记为“virtual”。然而,在 C++11 之前,它曾经是一个很好的实践,因为它对那些阅读代码的人来说是一个很好的提示(可能很难记住基类的所有虚函数)。

从 C++11 开始,派生类中有两个额外的关键字可以帮助提高可读性和代码的健壮性。它们是«override»和«final»。例如,将«override»放在派生类的方法中可以确保基类的相应方法实际上是虚拟的。«final» 关键字的作用相同,而且它可以防止该方法被进一步覆盖。

我还在我的博客(此处)中使用更多现实世界的基本原理和代码示例对此进行了描述。

希望能帮助到你。祝你好运!

于 2013-08-07T13:15:57.737 回答
8

没有。只是为了帮助提醒您哪些功能是虚拟的。

于 2013-08-07T13:06:07.883 回答
8

virtual仅在基类声明中是必需的。它在派生类中是可选的,在这些情况下可能主要用作提醒。

C++11 引入override使事情更加明确:它明确地将派生类中的方法标记为virtual基类方法的覆盖。

于 2013-08-07T13:10:35.923 回答
0

virtual 关键字在驱动类中是可选的,因为根据规则,当您使用具有虚函数的基类驱动类时,并且当您在驱动类编译器中覆盖虚拟函数时,会隐式分配虚拟关键字以及函数。因此,您不需要显式分配 virtual 关键字。但是这个关键字在多级继承期间是必需的。

例子:

在您的代码中,我们添加此代码。

   class derived: public base {
    public:
        virtual void method() {    // In this line virtual keyword is optional.
              std::cout << std::endl << "DERIVED :: method function" << std::endl;
        }

        virtual void display() {
              std::cout << std::endl << "DERIVED :: display function" << std::endl;
        }
   };

   class deriveChild: public derived {
        public:
            void method() {
                 std::cout << std::endl << "DERIVECHILD :: method" << std::endl;
            }

        void display() {
                 std::cout << std::endl << "DERIVECHILD:: display" << std::endl;
            }
   };

在 main() 中,如果您使用以下代码,它将为您提供不同的输出。

   base  *ptr = new deriveChild();
   ptr->method(); // will compile and execute
   ptr->display(); // will generate error because display() is not part of base class.

现在,如果您想使用派生儿童类的 display(),请使用此代码。

   derived *ptr = new deriveChild();
   ptr->method(); // Compile and Execute 
   ptr->display(); // Compile and Execute
于 2013-08-07T13:47:45.737 回答
0

派生类中的隐式虚拟方法在派生类中是虚拟的,不需要显式定义它们是虚拟的。如果声明它将是多余的声明。

ptr->method();

当编译器遇到上述语句时

-> 它将尝试解析上述语句,因为 method() 函数是虚拟的,编译器将该调用的解析推迟到运行时。

-> 当你在运行时创建了派生类的对象,现在编译器会知道这个方法是派生类的。

这个虚拟关键字在派生类中做了什么额外的事情?

考虑这种情况,还有一个名为 Derived2 的派生类继承了派生的形式,并且它有自己的虚拟方法。

 class derived2: public derived
{
public:
    virtual void method()
    {
        std::cout << std::endl << "DERIVED2" << std::endl;
    }
};

如果您在 main 中调用 method(),如下所示

int main()
{
    base* ptr = new derived2();
    ptr->method();   //derived2 class method() will get called
    return 9;
}

如果默认情况下derived2 中的method() 不是虚拟的,您最终将调用method() 的派生版本,失去运行时多态性的好处。

因此,c++ 的作者在这里做了出色的工作,使虚拟关键字继承分层。

于 2013-08-07T14:07:14.517 回答