Fat*_*eep 1 c++ polymorphism inheritance templates 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();
}
Run Code Online (Sandbox Code Playgroud)
这里的想法是编译器将在switch语句中的运行时生成所有模板化类型.模板在编译时是已知的,所以现在我们可以从基类中调用在派生类中被覆盖的虚方法.
这有效的唯一原因是因为每个类的函数具有相同的参数.如果我们在使用T的派生类中使用参数,那么它将无法工作.因此,我们将参数转换为派生类中的T以实现所需的行为.我注意到这只适用于C风格的演员.
洙...这里发生了什么样的未定义行为?
您的代码正好是100%经典的多态性,除了一个小错字:你Derived<T>
继承私下的Base
,而不是公开.
你写了:
template<typename T>
class derivedT : base {
// ^ bases, just like members, default to 'private'
Run Code Online (Sandbox Code Playgroud)
你应该写的:
template<typename T>
class derivedT : public base {
// ^^^^^^
Run Code Online (Sandbox Code Playgroud)
这就解释了为什么你必须使用"C风格"强制转换而不是简单的static_cast
从派生类到其私有基类.如果基地已经公开,static_cast
那就可以了.然后你的代码没有什么有趣的东西 - 它只是一个简单的"经典OOP",带有基类和几个派生类.
即使有私人基地,我相信这不是未定义的行为.当你调用虚方法时,你肯定没问题:你有一个类型的指针base*
,它实际上指向一个类型的对象base
,所以你没事.UB 可能进入的唯一地方就是你进行C风格的转换......但是在这里,编译器可以看到你正在将派生类转换为它的私有库,并且会使它工作.(允许C风格的强制转换绕过C++中的访问控制,但是它们仍然遵守其他规则.它们不会转向reinterpret_cast
.)
无论如何,这个问题似乎是CodeReview的主题.您应该做的是发布到StackOverflow,主题为"为什么在将指针Base
指向指针指向Derived
?时需要C样式转换".答案是,"你只是忘了使用public
继承."