从两个多态类继承

发布于 2024-08-20 01:12:01 字数 974 浏览 5 评论 0原文

鉴于以下代码,

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

Given the following code

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;
}

I get the output I would expect

bar
foo

However, if I change the definition of U to

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

I still compile fine and without warnings/errors but the output is now

bar
bar

What is it about the virtual declaration that prevents me from calling into the foo?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╰◇生如夏花灿烂 2024-08-27 01:12:01

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

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

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

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

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

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

Firstly, there are no virtual base classes in your example. Classes that contain virtual functions are called polymorphic. (There is such thing as "virtual base classes" in C++ but it has nothing to do with your example.)

Secondly, the behavior of your code does not depend on any virtual declarations. You have deliberately destroyed the integrity of the base pointer by using reinterpret_cast. For this reason the behavior of the code is undefined.

A direct cast from one base pointer to another (which is what you are trying to do in your code) is called cross-cast. The only cast in C++ that can carry out a cross-cast is dynamic_cast.

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

You can perform an indirect cross-cast without dynamic_cast, but for that you have to downcast the pointer to the derived type first (A *) using static_cast and then upconvert it to another base pointer type

t.push_back(static_cast<A *>(u[0])); // upconversion to `T *` is implicit
ぺ禁宫浮华殁 2024-08-27 01:12:01

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

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

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

If you use reinterpret_cast you loose all guarantees, and anything you do is "undefined behaviour". In this case, I expect the VMT got messed up, or the VPTR overwritten.

As an illustration, when I compile the first code above, I get a segfault on execution on my compiler.

If you really want to "cross-execute" you should derive from a common base class, and inherit that base class by U and T virtually ( : virtual public), or use dynamic_cast instead of reinterpret_cast.

最终幸福 2024-08-27 01:12:01

u 一样填充 t

t.push_back(a);

您不需要 reinterpret_cast,因为 AT

Populate t just like you did u:

t.push_back(a);

You don't need reinterpret_cast because A is a T.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文