【问题标题】:Inherit from two polymorphic classes从两个多态类继承
【发布时间】:2010-01-28 23:58:17
【问题描述】:

给定以下代码

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 的原因是什么?

【问题讨论】:

  • reinterpret_cast 是万恶之源。创建它只是为了让您的团队负责人知道在您的代码中使用 grep 来查找错误;)。
  • @KornelKisielewicz,这句话太棒了!
  • 您可以在任何指向TA 的指针上调用foofooU 无关。所以我不太明白你在U 中对“虚拟声明”的评论。

标签: c++ multiple-inheritance virtual-functions


【解决方案1】:

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

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

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

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

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

t.push_back(static_cast<A *>(u[0])); // upconversion to `T *` is implicit

【讨论】:

  • 更新主题以反映多态评论。
【解决方案2】:

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

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

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

【讨论】:

  • 谢谢。我不知道virtual public
  • @ezpz - 虚拟继承时的不同之处在于,您继承相同的基类,因此在具有公共基类时形成&lt;&gt; 而不是\/
【解决方案3】:

填充t,就像你做u

t.push_back(a);

您不需要reinterpret_cast,因为AT

【讨论】:

  • 我认为他明确不想那样。
  • 在我的特殊情况下,我无权访问推入向量中的原始对象,我只有向量本身中的对象。这就是我尝试做这一切的原因。
  • @ezpz,然后使用dynamic_cast,但请记住它可以返回NULL。
  • @KornelKisielewicz,我不明白他想避免什么。考虑到这一点,我认为 AndreyT 最接近他可能想要的答案。
猜你喜欢
  • 2011-09-04
  • 1970-01-01
  • 2011-10-01
  • 2010-09-23
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
相关资源
最近更新 更多