在成员函数内调用虚函数

时间:2010-03-02 13:27:54

标签: c++ polymorphism virtual-functions member-functions

我正在阅读布鲁斯·埃克尔的Thinking in C++。在第15章(第1卷)标题“构造函数内的虚函数的行为”标题下,他去了

  

如果你在里面会发生什么   构造函数,你称之为虚拟   功能?在普通会员里面   功能你可以想象会发生什么   发生 - 虚拟呼叫已解决   在运行时因为对象不能   知道它是否属于班级   成员函数在或某些   从中派生出来的类。对于   一致性,你可能会认为这是   里面应该发生什么   构造

这里Bruce试图解释当你在一个对象的构造函数中调用一个虚函数时,不会显示多态性,即只调用当前类的函数,它不会是该函数的其他派生类版本。这是有效的,我可以理解它,因为类的构造函数不会事先知道它是为它运行还是为了另一个被创建的对象。而且,如果它这样做,它将在部分创建的对象上调用函数,这是灾难性的。

虽然我的混乱突然出现,因为他说的是关于普通会员功能的第一句话,他说虚拟呼叫将在@运行时解决。但等等,在一个类的任何成员函数内,当你调用另一个函数(无论是虚拟还是非虚函数)时,它自己的类版本只会被调用,对吧? E.g。

class A
{
    virtual void add() { subadd(); }
    virtual subadd() { std::cout << "A::subadd()\n"; }
};

class B : public A
{
    void add() { subadd(); }
    void subadd() { std::cout << "B::subadd()\n"; }
};

在上面的代码中,A::add()在调用subadd()时,总是调用A::subadd(),同样适用于{ {1}},对吧?那么他的意思是“虚拟调用是在运行时解决的,因为对象无法知道它是属于成员函数所在的类,还是某个派生自它的类”?

他是否通过基类指针对调用进行了解释? (我真的很怀疑)在这种情况下,他不应该写“在一个普通的成员函数里面”;根据我的理解,到目前为止,同一个类的另一个成员函数中的成员函数的任何调用都不是多态的,如果出错,请纠正我。

3 个答案:

答案 0 :(得分:6)

你错了 - 另一个派生类可以覆盖一些虚函数,这意味着静态调用会出错。所以,扩展你的例子:

class C : public B
{
public:
    // Not overriding B::add.
    void subadd() { std::cout << "C::subadd\n"; }
};

A *a = new C;
a->add();

这会动态调用B::add,然后动态调用C::subadd。对B::subadd的静态调用是错误的,因为动态类型为CC会覆盖该函数。

在您的示例中,A::add复制为B::add是不必要的 - 无论对象的动态类型如何,两者都会以多态方式调用subadd

答案 1 :(得分:3)

  

当你调用另一个函数(无论是虚拟还是非虚拟)时,它自己的类版本只会被调用,对吧?

抱歉,错了。构造函数是例外。否则,您正在处理完全构造的对象,其中存在完整的多态性。在后面的例子中(如果B继承自A),所谓的是B::subadd()(只需要获取测试驱动的代码:这是了解编程语言如何工作的最佳方式)。

答案 2 :(得分:1)

示例中的电话subadd();实际上就是电话this->subadd();。在A::add()中,this的类型为A*,但this可能指向C对象(假设C也来自A)。编译A::add()时,编译器无法知道class C中是否覆盖了哪些虚函数。 this->subadd();中的来电A::add()实际上可能会调用C::subadd()。因此,编译器别无选择,只能进行虚拟调用,以便在知道this->指向的位置时在运行时进行解析。