运行时数据类型多态

时间:2018-08-05 19:22:56

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

我为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样式的投射。

S ...这是什么样的未定义行为?

1 个答案:

答案 0 :(得分:5)

您的代码完全是 100%经典多态性,除了一个小的错字:您有Derived<T>Base继承 private 而不是公开。

您写道:

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”,具有一个基类和几个派生类。

即使有私人基础,我相信这也是 not 未定义的行为。到您调用虚拟方法时,您肯定还可以:您拥有类型为base*的指针,并且它实际上指向类型为base的对象,因此您可以。 UB 可能唯一可以进入的地方是您进行C样式的转换...但是在这里编译器可以看到,您正在将派生类转换为其私有基础,并将使工作。 (允许C样式的强制转换绕过C ++中的访问控制,但是它们仍然遵守其他规定,但不附带任何限制。它们不会移交给reinterpret_cast。)

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