C++ 在成员函数内调用虚拟函数
我在读布鲁斯·埃克尔的作品。在第15章(第1卷)的标题“构造函数中虚函数的行为”下,他说 如果你在一个房间里会发生什么 构造函数,然后调用虚拟 功能?普通成员内部 你可以想象会发生什么 发生–虚拟呼叫已解决 在运行时,因为对象无法 知道它是否属于这个班 成员函数在中或某些中 类从中派生。对于 一致性,你可能认为这是 里面会发生什么 构造器 这里Bruce试图解释,当你在一个对象的构造函数中调用一个虚拟函数时,多态性不会被显示出来,也就是说,当前类的函数只会被调用,而不会是该函数的其他派生类版本。这是有效的,我可以理解,因为类的构造函数事先不会知道它是为它运行还是为其他dervied对象的创建运行。此外,如果这样做,它将调用部分创建的对象上的函数,这是灾难性的 当我突然感到困惑时,因为他在第一句中陈述了普通成员函数,他说虚拟调用将在运行时解决。但是等等,在一个类的任何成员函数中,当您调用另一个函数(无论是虚拟的还是非虚拟的)时,它自己的类版本将只被调用,对吗?例如C++ 在成员函数内调用虚拟函数,c++,polymorphism,virtual-functions,member-functions,C++,Polymorphism,Virtual Functions,Member Functions,我在读布鲁斯·埃克尔的作品。在第15章(第1卷)的标题“构造函数中虚函数的行为”下,他说 如果你在一个房间里会发生什么 构造函数,然后调用虚拟 功能?普通成员内部 你可以想象会发生什么 发生–虚拟呼叫已解决 在运行时,因为对象无法 知道它是否属于这个班 成员函数在中或某些中 类从中派生。对于 一致性,你可能认为这是 里面会发生什么 构造器 这里Bruce试图解释,当你在一个对象的构造函数中调用一个虚拟函数时,多态性不会被显示出来,也就是说,当前类的函数只会被调用,而不会是该函数的其他派生类版本。
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类
{
虚拟空添加(){subadd();}
虚拟子添加(){std::cout
当您调用另一个函数(无论是虚拟函数还是非虚拟函数)时,只会调用它自己的类版本,对吗
抱歉,错了。构造函数是例外。否则,您将处理一个完全构造的对象,该对象具有完全多态性。在后面的示例中(如果B从a继承),称为B::subadd()
(只需对代码进行试驾:这确实是学习编程语言如何工作的最好方法)
当您调用另一个函数(无论是虚拟函数还是非虚拟函数)时,只会调用它自己的类版本,对吗
抱歉,错了。构造函数是例外。否则,您将处理一个完全构造的对象,该对象具有完全多态性。在后面的示例中(如果B从a继承),称为B::subadd()
(只需将代码用于试驾:这确实是学习编程语言如何工作的最佳方式)。示例中的调用subadd();
实际上就是调用this->subadd();
,this的类型是A*
,但是this
可能指向C
对象(假设C也是从A派生的)。编译A::add()
时,编译器无法知道在类C
中重写了哪些虚拟函数。中的调用this->subadd();
实际上可能调用C::subadd()
。因此,编译器别无选择,只能进行一个虚拟调用,当它知道此->
指向何处时,将在运行时解析。示例中的调用subadd();
实际上就是中的调用此->subadd();
,this的类型是A*
,但是this
可能指向C
对象(假设C也是从A派生的)。编译A::add()
时,编译器无法知道在类C
中重写了哪些虚拟函数。中的调用this->subadd();
实际上可以调用C::subadd()
。因此,编译器别无选择,只能进行一个虚拟调用,当它知道这个->
指向何处时,将在运行时进行解析。您错了-进一步的派生类可能会覆盖一些虚拟函数,这意味着静态调用将是错误的。因此,扩展您的示例:
class C : public B
{
public:
// Not overriding B::add.
void subadd() { std::cout << "C::subadd\n"; }
};
A *a = new C;
a->add();
C类:公共B类
{
公众:
//不重写B::add。
void subadd(){std::cout add();
这将动态调用B::add
,后者又动态调用C::subadd
。对B::subadd
的静态调用将是错误的,因为动态类型是C
,而C
将覆盖该函数
在您的示例中,将
A::add
复制为B::add
是不必要的-无论对象的动态类型如何,两者都将以多态方式调用subadd
。您错了-进一步派生的类可能会覆盖一些虚拟函数,这意味着静态调用将是错误的。因此,为了扩展您的检查ple:
class C : public B
{
public:
// Not overriding B::add.
void subadd() { std::cout << "C::subadd\n"; }
};
A *a = new C;
a->add();
C类:公共B类
{
公众:
//不重写B::add。
void subadd(){std::cout add();
这将动态调用B::add
,后者又动态调用C::subadd
。对B::subadd
的静态调用将是错误的,因为动态类型是C
,而C
将覆盖该函数
在您的示例中,将
A::add
复制为B::add
是不必要的-无论对象的动态类型如何,两者都将以多态方式调用subadd
。现在这是“试一试”的好例子。我在发布之前已经试过了,它只显示了各自的成员函数,就像我上面写的。如果你想让B从A派生,你没有告诉编译器。@Eric:谢谢,修复了它!现在这是“试试看”的好例子。我在发布之前已经尝试过了,它只显示了各自的成员函数,就像我上面写的。如果你想让B从A派生,你没有告诉编译器。@Eric:谢谢,修复了它!啊:我没有读代码,但是你想的是什么。你肯定想让B从A继承吗?是的,很抱歉,我没有在发布中正确地编写它,fi我没有读代码,但是你想读的。你肯定读过了