2

给定以下代码

class T {
    public:
        virtual ~T () {}
        virtual void foo () = 0;
};

class U {
    public:
        U() {}
        ~U() {}
        void bar () { std::cout << "bar" << std::endl; }
};

class A : public U, public T {
    public:
        void foo () { std::cout << "foo" << std::endl; }
};

int main () {
    A * a = new A;

    std::vector<U*> u;
    std::vector<T*> t;

    u.push_back(a);

    t.push_back(reinterpret_cast<T*>(u[0]));

    u[0]->bar ();
    t[0]->foo ();

    delete a;
    return 0;
}

我得到了我期望的输出

bar
foo

但是,如果我将定义更改U

class U {
    public:
        U() {}
        virtual ~U() {}
        virtual void bar () { std::cout << "bar" << std::endl; }
};

我仍然可以正常编译并且没有警告/错误,但现在是输出

bar
bar

阻止我调用的虚拟声明是foo什么?

4

3 回答 3

4

首先,您的示例中没有虚拟基类。包含虚函数的类称为多态类。(C++ 中有“虚拟基类”之类的东西,但它与您的示例无关。)

其次,代码的行为不依赖于任何虚拟声明。您使用 . 故意破坏了基指针的完整性reinterpret_cast。由于这个原因,代码的行为是未定义的。

从一个基指针到另一个基指针的直接转换(这是您在代码中尝试执行的操作)称为cross-cast。C++ 中唯一可以进行交叉转换的转换是dynamic_cast.

t.push_back(dynamic_cast<T *>(u[0])); 

您可以在没有 的情况下执行间接交叉dynamic_cast转换,但为此您必须首先A *使用 ( )将指针向下转换为派生类型static_cast,然后将其向上转换为另一个基本指针类型

t.push_back(static_cast<A *>(u[0])); // upconversion to `T *` is implicit
于 2010-01-29T00:05:35.443 回答
1

如果您使用reinterpret_cast您将失去所有保证,并且您所做的任何事情都是“未定义的行为”。在这种情况下,我预计 VMT 搞砸了,或者 VPTR 被覆盖了。

作为说明,当我编译上面的第一个代码时,我在编译器上执行时遇到了段错误。

如果您真的想“交叉执行”,您应该从一个公共基类派生,并通过 U 和 T虚拟继承该基类( : virtual public),或者dynamic_cast使用reinterpret_cast.

于 2010-01-29T00:04:36.510 回答
0

t像你一样填充u

t.push_back(a);

你不需要reinterpret_cast,因为A是一个T.

于 2010-01-29T00:05:37.877 回答