C ++简单多态问题

时间:2010-10-07 16:52:12

标签: c++ polymorphism

好的我承认,我是一个完全的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编译了这个,发生了两件事:

  1. 首先,行p->f()
  2. 中没有“异常终止”
  3. 在发生“异常终止”的行中调用object3的方法h()
  4. 程序的输出是:

    Class1中的函数f() Class1中的函数g() Class2中的函数f() Class1中的函数g() 函数h()在Class3中 Class1中的函数g()

    我试图理解为什么会这样,但对我来说这似乎太奇怪了。

    任何帮助都会很棒。

    提前致谢!

4 个答案:

答案 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)

这个例子是可恶的,不应该出现在印刷品中。 是多态性的一个例子。

通过将对象转换为不相关的类指针,他正在调用未定义的行为。由于它是未定义的,因此你得到的结果与他相比并不奇怪。