【问题标题】:Runtime Datatype polymorphism运行时数据类型多态性
【发布时间】:2018-08-05 19:22:55
【问题描述】:

我想出了一个 C++ 运行时多态性的解决方案。

#include <iostream>
using namespace std;

class base {
    public:
    virtual void call(double xx) {
        cout << "DERIVED: " << xx << endl;
    }
};

template<typename T>
class derivedT : base {
    public:
    virtual void call(double xx) {
        cout << "DERIVED_T: " << ((T) xx) << endl;
    }
};

int main() {
    base* sample = nullptr;

    cout << "CHOOSE TYPE: (BYTE = 1, UINT = 2, DOUBLE = 3)" << endl;
    uint8_t type = cin.get();
    type -= 48;

    switch (type) {
        case 1:
            sample = (base*) new derivedT<uint8_t>();
        break;
        case 2:
            sample = (base*) new derivedT<uint32_t>();
        break;
        case 3:
            sample = (base*) new derivedT<double_t>();
        break;
    }

    sample->call(2567.45);
    cin.get();
    cin.get();
}

这里的想法是编译器将在运行时在 switch 语句中生成所有模板化类型。 模板在编译时是已知的,所以现在我们可以从在派生类中被覆盖的虚拟基类。

唯一可行的原因是每个类的函数具有相同的参数。如果我们要在使用 T 的派生类中使用参数,那么它将不起作用。因此,我们将参数转换为派生类中的 T 以实现所需的行为。我注意到这只适用于 C 风格的转换。

Soo...这里发生了什么样的未定义行为?

【问题讨论】:

  • “编译器将在运行时生成所有模板化类型”:不,它将在编译时生成所有模板实例化。 switch 只会选择在运行时使用哪一个。

标签: c++ templates inheritance polymorphism c++17


【解决方案1】:

您的代码完全是 100% 的经典多态,除了一个小错字:您有 Derived&lt;T&gt;Base 继承私有,而不是公开继承。 p>

你写道:

template<typename T>
class derivedT : base {
//               ^ bases, just like members, default to 'private'

你应该写:

template<typename T>
class derivedT : public base {
//               ^^^^^^

这解释了为什么必须使用“C 风格”转换而不是简单的static_cast 来从派生类到其私有基类。如果基地是公开的,static_cast 会工作得很好。然后你的代码就没有什么有趣的了——它只是一个简单的“经典 OOP”,有一个基类和几个派生类。

即使是私人基地,我相信这不是未定义的行为。当你调用虚方法时,你肯定没问题:你有一个base* 类型的指针,它实际上指向一个base 类型的对象,所以你没问题。 UB 可能 蔓延的唯一地方是您进行 C 风格转换的地方...但是在这里编译器可以看到您正在将派生类转换为其私有基类,并将使其工作。 (C 风格的强制转换可以绕过 C++ 中的访问控制,但它们仍然遵守其他规则 w.r.t. upcasts。它们不会演变为 reinterpret_cast。)

无论如何,这个问题对于 CodeReview 来说似乎是题外话。您应该做的是在 StackOverflow 上发布主题行“为什么我需要 C 样式转换时将指针到Base 到指针到Derived?”。答案是,“你只是忘了使用public 继承。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 2014-06-02
    • 2020-03-05
    • 2016-02-03
    相关资源
    最近更新 更多