【问题标题】:C++ Virtual function implementation?C++虚函数实现?
【发布时间】:2010-12-13 09:07:15
【问题描述】:

如果我有 C++:

class A {
    private: virtual int myfunction(void) {return 1;}
}

class B: public A {
    private: virtual int myfunction(void) {return 2;}
}

如果我从class B 中的myfunction 定义中删除virtual,这是否意味着如果我有一个基于class Bclass C,我就无法覆盖myfunction,因为它会被静态编译吗?

另外,我很困惑当你在这里切换公共和私人时会发生什么。如果我将class Bmyfunction 的定义更改为公开(class A 中的定义保持私有),这是我不应该做的某种严重错误吗?我认为虚函数需要保持相同的类型,所以这是非法的,但如果有错请告知。

谢谢!

【问题讨论】:

  • 派生类方法不需要显式编写“virtual”关键字。你可以省略它,但拥有它是一种很好的风格。

标签: c++ inheritance virtual


【解决方案1】:

virtual 的行为是,当您有一个指向子类型对象的一种类型的指针时,它会影响调用哪个方法。例如:

B* obj = new B;
A* base = obj;

调用obj->myfunction() 时会发生什么取决于A 是否声明myfunction 是虚拟的。如果不是虚的,推理是:我们有一个A类型的指针,所以我们调用A中定义的函数,结果是1。如果A定义myfunction是虚的,然而,然后在运行时根据实际对象的类型而不是指针的类型进行查找;由于对象实际上是B,所以使用B中定义的实现,结果为2。

更多信息请访问the C++ FAQ Lite section on virtual functions

【讨论】:

    【解决方案2】:

    “虚拟”的第一个定义是最重要的。来自 base 的该函数从那时起在派生时是虚拟的,这意味着您不需要“虚拟”来重新实现虚拟函数调用。如果基类中的函数签名不是虚函数,而在派生类中是虚函数,则基类不具有多态行为。

    class Base
    {
        public:
        void func(void){ printf("foo\n"); }
    };
    class Derived1 : public Base
    {
        public:
        virtual void func(){ printf("bar\n"); }
    };
    class Derived2 : public Derived1
    {
        public:
        /*  reimplement func(), no need for 'virtual' keyword
            because Derived1::func is already virtual */
        void func(){ printf("baz\n"); } 
    };
    
    int main()
    {
        Base* b = new Derived1;
        Derived1* d = new Derived2;
    
        b->func(); //prints foo - not polymorphic
        d->func(); //prints baz - polymorphic
    }
    

    【讨论】:

    • 不客气。我还应该补充一点,“Base* b”实际上是一个 Derived1。使用 dynamic_cast 在您需要的情况下执行安全的向下转换。
    • 但是作者的例子涵盖了私人成员。
    • @bua : 与使用模板时的依赖/独立名称查找不同,虚拟调用的名称查找不受访问说明符的影响。
    • 例子太好了
    【解决方案3】:

    如果您从 B 类的 myfunction 定义中删除 virtual

    编译器会为你添加这个。为多态类型填写V-Table。

    !!但是!!

    您将只能访问 A 类的公共成员(B 类:public A)

    定义:

    class B: private A
    {
    
    }
    

    将导致 A 类的所有(甚至是公共的)成员都将变为 B 类的私有成员。 简化您将无法访问 A 公共成员。

    解决方法你可以声明一些朋友:

    class A
    {
        private:
            friend class B;
    }
    

    更多精彩信息HERE

    【讨论】:

    • 答案让我有点困惑。从答案中我读到B类无法访问他从A类继承的公共成员,然后通过声明A的B朋友来解决这个问题。我认为这是不对的。 B 可以访问来自 A 的公共和受保护成员,但 B 的用户不能访问 A 的公共成员,这不会通过朋友声明来解决。我是不是误解了什么?
    • 是的,您错过了我的示例中的私有继承。
    • 好的,那么我建议您重新阅读链接上的信息:B 类可以从他的私人继承的 A 类中访问所有公共和受保护的成员,无论朋友还是非朋友。
    • 乐观地说,也许他们的意思不是 B 不能访问从 A 继承的成员,而是 B 的外部用户不能通过 B 的接口访问 A 的(以前是公共的)成员。无论哪种方式,这个答案的措辞都很糟糕,并且与问题的相关性令人怀疑。
    【解决方案4】:

    一旦一个函数在基类中被设置为虚函数,它对于所有其他子类都是虚函数。

    public、protected 和 private 不会影响函数的虚拟性质。

    【讨论】:

    • 谢谢!感谢您提供可见性信息。
    • 通过使您的虚函数受保护或私有,您可以提示您的类的用户是否需要在子类中调用它们。 gotw.ca/publications/mill18.htm
    猜你喜欢
    • 1970-01-01
    • 2011-09-02
    • 2012-04-22
    • 2011-05-28
    • 2013-07-19
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多