Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在成员函数内调用虚拟函数_C++_Polymorphism_Virtual Functions_Member Functions - Fatal编程技术网

C++ 在成员函数内调用虚拟函数

C++ 在成员函数内调用虚拟函数,c++,polymorphism,virtual-functions,member-functions,C++,Polymorphism,Virtual Functions,Member Functions,我在读布鲁斯·埃克尔的作品。在第15章(第1卷)的标题“构造函数中虚函数的行为”下,他说 如果你在一个房间里会发生什么 构造函数,然后调用虚拟 功能?普通成员内部 你可以想象会发生什么 发生–虚拟呼叫已解决 在运行时,因为对象无法 知道它是否属于这个班 成员函数在中或某些中 类从中派生。对于 一致性,你可能认为这是 里面会发生什么 构造器 这里Bruce试图解释,当你在一个对象的构造函数中调用一个虚拟函数时,多态性不会被显示出来,也就是说,当前类的函数只会被调用,而不会是该函数的其他派生类版本。

我在读布鲁斯·埃克尔的作品。在第15章(第1卷)的标题“构造函数中虚函数的行为”下,他说

如果你在一个房间里会发生什么 构造函数,然后调用虚拟 功能?普通成员内部 你可以想象会发生什么 发生–虚拟呼叫已解决 在运行时,因为对象无法 知道它是否属于这个班 成员函数在中或某些中 类从中派生。对于 一致性,你可能认为这是 里面会发生什么 构造器

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

当我突然感到困惑时,因为他在第一句中陈述了普通成员函数,他说虚拟调用将在运行时解决。但是等等,在一个类的任何成员函数中,当您调用另一个函数(无论是虚拟的还是非虚拟的)时,它自己的类版本将只被调用,对吗?例如

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我没有读代码,但是你想读的。你肯定读过了