我的代码下面是带有虚函数的链继承,它打印出来:
D ptr
E
那么函数匹配的算法是什么,我的猜测是它匹配最近的父类?但是& e基本上是A *,B *,D *类型,为什么这甚至编译并且使用这个属性是好的做法?
#include <iostream>
using namespace std;
class A {
public:
virtual void f(){cout<<"A";};
};
class B :public A {
public:
virtual void f() {
cout<<"B";
}
};
class D : public B {
public:
virtual void f() {
cout<<"D";
}
};
class E : public D {
public:
virtual void f() {
cout<<"E";
}
};
void f(D *sth) {
cout<<"D ptr"<<endl;
sth->f();
}
void f(B *sth) {
cout<<"B ptr"<<endl;
sth->f();
}
void f(A *sth) {
cout<<"A ptr"<<endl;
sth->f();
}
int main() {
E e;
f(&e);
}
答案 0 :(得分:0)
我会尽力打破你的榜样:
int main() {
E e; // declare object of Class E
f(&e); // run f() function and pass it the address of E
}
好的很简单 - 您声明了一个E类对象,然后在其上运行了一个函数。现在全局f()函数已经重载三次以接受指向D对象,B对象或A对象的地址的指针。由于所有这些都将对象更高地放在继承树上,因此任何对象都适用于E类对象。编译器将为最派生类选择函数。在这种情况下,选择void f(D * sth)函数。
void f(D *sth) {
cout<<"D ptr"<<endl; // "D ptr" printed to screen
sth->f(); // Take original pointer to class E object and
// run its own class method f() on it
}
然后查看E的类定义,我们将看到E打印的原因:
class E : public D {
public:
virtual void f() {
cout<<"E";
}
};
如果你要注释掉void f(D * sth)函数,编译器会改为选择void f(B * sth)函数,从而得到输出&#34; B ptr&#34;和&#34; E&#34;。如果您要注释掉A和B对象的全局f()函数,然后尝试在B对象上运行void f(D * sth),它将无法编译,因为编译器只能将对象转换为继承树,而不是它。
正如Phil1970评论的那样,这种结构通常不受欢迎,因为它依赖于具有继承树知识的全局函数。
答案 1 :(得分:0)
它应该给你一个未定义的行为或歧义。不同的编译器版本可以提供不同的结果,因此您最好不要依赖于您的结果:)