好的我承认,我是一个完全的C ++ noob。
我正在检查Adam Drozdek在C ++中的数据结构和算法,在第1.5节:“多态性”中他提出了下一个例子:
class Class1
{
public:
virtual void f()
{
cout << "Function f() in Class1" << endl;
}
void g()
{
cout << "Function g() in Class1" << endl;
}
};
class Class2
{
public:
virtual void f()
{
cout << "Function f() in Class2" << endl;
}
void g()
{
cout << "Function g() in Class2" << endl;
}
};
class Class3
{
public:
virtual void h()
{
cout << "Function h() in Class3" << endl;
}
};
int main()
{
Class1 object1, *p;
Class2 object2;
Class3 object3;
p = &object1;
p->f();
p->g();
p = (Class1*)&object2;
p->f();
p->g();
p = (Class1*)&object3;
p->f(); // Abnormal program termination should occur here since there is
// no f() method in object3, instead object3->h() is called
p->g();
//p->h(); h() is not a member of Class1
return 0;
}
我使用Visual Studio 2010编译了这个,发生了两件事:
p->f()
h()
。程序的输出是:
Class1中的函数f() Class1中的函数g() Class2中的函数f() Class1中的函数g() 函数h()在Class3中 Class1中的函数g()
我试图理解为什么会这样,但对我来说这似乎太奇怪了。
任何帮助都会很棒。
提前致谢!
答案 0 :(得分:12)
如果那是本书所使用的代码,请立即将书籍丢入垃圾箱。多态性在继承上起作用,例如
class Class2 : public Class1
如果没有这个,就没有正确计划的希望。
作者似乎试图通过使用
来规避要求(即,编译错误的程序)p = (Class1*)&object2;
这是一个C风格的演员表,它被解释为C ++
p = reinterpret_cast< Class1 * >( &object2 );
reinterpret_cast
是一个危险的运算符,绝不应该在两个多态类型之间使用。这是应该使用的:
// use only if dynamic type of object2 is same as static type:
p = static_cast< Class1 * >( &object2 );
// Will not compile unless you add : public Class1
或
// returns NULL if object2 dynamic type not derived from Class1
p = dynamic_cast< Class1 * >( &object2 );
至于“异常终止”,我认为作者正在描述代码如何在他的机器上崩溃。但是,这并不是因为语言说它应该。他刚写了一个不正确的程序,可能会在某些机器上崩溃而在其他机器上崩溃。
答案 1 :(得分:1)
h()
可能与Class3的vtable中的位置相同,f()
适用于Class1和Class2。 vtable是一个存储在对象中的表,其中包含虚方法的地址,因此运行时甚至可以从不同类型的指针调用正确的方法。
这是一个没有任何继承的奇怪示例。像这样的演员不是很安全,我怀疑这是便携式的。
答案 2 :(得分:0)
编译器编译时绑定到虚拟表的第一个元素,因为p类型为Class1,它看到它有方法f()。但实际上当你运行程序时,它实际上得到了h()的句柄,其地址存储在虚拟表的第一个位置。
答案 3 :(得分:0)
这个例子是可恶的,不应该出现在印刷品中。 不是多态性的一个例子。
通过将对象转换为不相关的类指针,他正在调用未定义的行为。由于它是未定义的,因此你得到的结果与他相比并不奇怪。