C++ c++;危险铸造规范

C++ c++;危险铸造规范,c++,inheritance,polymorphism,dynamic-cast,static-cast,C++,Inheritance,Polymorphism,Dynamic Cast,Static Cast,我很确定这是危险的密码。然而,我想看看是否有人知道到底会出什么问题 假设我有这样的类结构: 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 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 {};
这样做的基本原理是,我正在使用一个类似于Test的类,但是为了使它当前工作,必须创建一个新的实例T(即Test),同时复制传递的实例。若我能将测试指向T的内存地址,那个就太好了

若Base并没有添加虚拟析构函数,并且由于测试并没有添加任何内容,我认为这段代码实际上是可以的。然而,虚拟析构函数的添加让我担心类型信息可能会被添加到类中。如果是这种情况,那么它可能会导致内存访问冲突


最后,我可以说这段代码在我的计算机/编译器(clang)上运行良好,当然,这并不能保证它不会对内存造成不良影响和/或不会在另一个编译器/机器上完全失败。

只要您不使用
Test*
执行任何操作,并且避免任何像智能指针或自动内存管理这样的魔法,您就应该没事了

您应该确保查找模糊的代码,例如检查对象的调试打印或日志记录。我曾经因为试图查看像这样设置的指针的值而被调试器撞坏。我敢打赌这会给你带来一些痛苦,但你应该能够让它起作用


我认为真正的问题是维护。开发人员在
Test*
上执行操作需要多长时间?

只要您不使用
Test*
执行任何操作,并且避免任何像智能指针或自动内存管理这样的魔法,您就可以了

您应该确保查找模糊的代码,例如检查对象的调试打印或日志记录。我曾经因为试图查看像这样设置的指针的值而被调试器撞坏。我敢打赌这会给你带来一些痛苦,但你应该能够让它起作用


我认为真正的问题是维护。需要多长时间,开发人员才能对
Test*
执行操作?

删除指针时,将调用虚拟析构函数
Base::~Base
。因为
B
没有合适的vtable(在这里发布的代码中根本没有),所以不会很好地结束


它只在这种情况下有效,因为您有内存泄漏,您永远不会删除
test

当您删除指针时,将调用虚拟析构函数
Base::~Base
。因为
B
没有合适的vtable(在这里发布的代码中根本没有),所以不会很好地结束


它只在这种情况下有效,因为您有内存泄漏,您永远不会删除
test

您的代码会产生未定义的行为,因为它违反了严格的别名。即使没有,您也在调用UB,因为B和A都不是多态类,并且指向的对象不是多态类,因此
dynamic_cast
无法成功。使用
dynamic\u cast
时,您试图访问不存在的基本对象以确定运行时类型

我能做出的一个非常重要的保证是 nor测试将没有任何其他成员变量或方法。他们是 本质上是空类


这一点都不重要,完全无关。标准必须强制要求EBO才能使其起作用,但事实并非如此。

您的代码会产生未定义的行为,因为它违反了严格的别名。即使没有,您也在调用UB,因为B和A都不是多态类,并且指向的对象不是多态类,因此
dynamic_cast
无法成功。使用
dynamic\u cast
时,您试图访问不存在的基本对象以确定运行时类型

我能做出的一个非常重要的保证是 nor测试将没有任何其他成员变量或方法。他们是 本质上是空类


这一点都不重要,完全无关。标准必须强制要求EBO才能让它开始起作用,但事实并非如此。

如果需要传递不透明指针,为什么不使用
void*
。它将使含义明确,并避免有人试图在
Test*
上执行操作的风险。不使用
void*
的原因是我在代码后面使用了
dynamic\u cast
(如
main
中所做的)。另外,
Test
仅在内部使用,不能从外部访问。当用户访问它时,它要么是
T*
,要么是指向
T
父级的指针。如果需要传递不透明指针,为什么不直接使用
void*
。它将使含义明确,并避免有人试图在
Test*
上执行操作的风险。不使用
void*
的原因是我在代码后面使用了
dynamic\u cast
(如
main
中所做的)。另外,
Test
仅在内部使用,不能从外部访问。当用户访问它时,它要么是
T*
,要么是指向
T
父项的指针。它是用于库的,测试将完全隐藏。它只在有人在我的代码中包装了他们的类T时使用,因此用户甚至看不到使用的类。。我本来打算打开内存保护,看看会发生什么,但问题是,即使它在我的机器上工作,我担心其他人的编译器可能会做一些非常不同的事情。它是用于库的,测试将完全隐藏。它只在有人在我的代码中包装他们的类T时使用,因此用户甚至看不到使用的类
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;
}