【发布时间】:2023-04-07 14:52:02
【问题描述】:
我很确定这是危险代码。但是,我想看看是否有人知道 究竟会出什么问题。
假设我有这样的类结构:
class A {
protected:
int a;
public:
A() { a = 0; }
int getA() { return a; }
void setA(int v) { a = v; }
};
class B: public A {
protected:
int b;
public:
B() { b = 0; }
};
然后假设我想要一种像这样自动扩展类的方法:
class Base {
public:
virtual ~Base() {}
};
template <typename T>
class Test: public T, public Base {};
我可以做出的一个真正重要保证是Base 和Test 都不会有任何其他成员变量或方法。它们本质上是空类。
(潜在的)危险代码如下:
int main() {
B *b = new B();
// dangerous part?
// forcing Test<B> to point to to an address of type B
Test<B> *test = static_cast<Test<B> *>(b);
//
A *a = dynamic_cast<A *>(test);
a->setA(10);
std::cout << "result: " << a->getA() << std::endl;
}
这样做的基本原理是我正在使用类似于 Test 的类,但为了使其当前工作,必须创建一个新实例 T(即 Test),并复制传递的实例。如果我可以将 Test 指向 T 的内存地址,那就太好了。
如果 Base 没有添加虚拟析构函数,并且由于 Test 没有添加任何内容,我认为这段代码实际上是可以的。但是,添加虚拟析构函数让我担心类型信息可能会添加到类中。如果是这种情况,那么它可能会导致内存访问冲突。
最后,我可以说这段代码在我的计算机/编译器 (clang) 上运行良好,尽管这当然不能保证它不会对内存造成不良影响和/或不会在另一个编译器/机器上完全失败。
【问题讨论】:
-
如果您需要传递不透明的指针,为什么不直接使用
void*。它将使含义清晰,并避免有人试图对Test<B>*执行操作的风险。 -
不使用
void *的原因是我在后面的代码中使用了dynamic_cast(和main一样)。此外,Test<T>只能在内部使用,不能从外部访问。当用户访问它时,它要么是T *,要么是指向T的父级的指针。
标签: c++ inheritance polymorphism dynamic-cast static-cast