我为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 ...这是什么样的未定义行为?
答案 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
继承。”