C++ 在基类没有虚方法的派生类中声明虚方法是错误的吗?

C++ 在基类没有虚方法的派生类中声明虚方法是错误的吗?,c++,inheritance,C++,Inheritance,例如: // No virtual methods in Base class Base { public: Base() {} ~Base() {} void Foo(); }; // Derived class containing virtual methods -- will this cause problems?? class Derived : public Base { public: Derived() {} virtual ~Derived() {}

例如:

// No virtual methods in Base
class Base
{
public:
  Base() {}
  ~Base() {}
  void Foo();
};

// Derived class containing virtual methods -- will this cause problems??
class Derived : public Base
{
public:
  Derived() {}
  virtual ~Derived() {}
  virtual void Bar() {}
};
我已经读到,在基类中声明至少一个虚(和/或纯虚)函数将隐式地导致所有派生类将virtual关键字应用于基类中定义的相同(虚)方法。这是有道理的

昨天我读到一篇评论,其中@Aaron McDaid指出:

。。。如果您有一个非虚拟基类,并且在派生类中有一些虚拟方法,那么Base*b=new-Derived();删除b;将是未定义的行为,可能会使程序崩溃。它看起来很安全,但不是。(这是因为b不会指向派生对象的“开始”-它将被vtable所需的空间偏移。然后,删除操作将不会在与新地址完全相同的地址上进行,因此它不是一个可释放的有效地址。如果要在任何地方使用虚拟方法,请在基地址中放置一个虚拟d'tor

这听起来对我来说是有道理的——有人知道它是否准确吗?如果它是准确的,为什么C++不隐式地使一个基本方法(例如析构函数)虚拟化,以保持VTAT在前面,并防止未定义的行为?< /P> 有没有一个不希望这种情况发生的例子

编辑:
如果基类不包含虚方法,则在派生类中声明(并使用)虚方法是否安全?

如果是非虚析构函数,则只调用基类的析构函数,如果派生类中存在未定义/未设置的基类成员,则会导致崩溃(尽管情况并非总是如此)

引用中提到的情况在多重继承的情况下是可能的,因为给定基类可能有不同的偏移量。从内存结构来看,继承的类包含在类中

 _____________________________
| Base class 1                |
 _____________________________
| Base class 2                |
|    .......                  |
 -----------------------------
在上述情况下,如果您试图使用基类2指针来删除或执行任何操作,您可能会遇到问题,除非您从对象地址获取偏移量。对于基类1指针,您不应该遇到任何问题

C++并没有将其隐式化,因为继承可能有不同的用途。此外,虚拟函数有性能损失。有时,人们不需要虚拟析构函数,因为基类只用于取出一些常见的东西,基类不用于引用对象(根据OOPs的概念,这可能是不正确的)C++也支持不同于其他语言的私有继承和受保护继承。使用派生对象作为基类没有任何意义。 不想使用虚函数的示例是私有继承,这意味着派生类是根据基类而不是基类来实现的。例如,堆栈可以使用数组来实现。您可以在堆栈中有一个数组对象,也可以私有地派生数组

class Stack: private Array {
  //Implement function using Array
}
显然,
Stack
在本例中不再是一个
Array
。因此,不需要在
Array
中使用虚拟析构函数。即使使用,由于私有继承,也无法释放
Stack
。 还有许多其他可能的情况


在您的情况下,您可能不会面临崩溃,但派生类的成员将无法释放并导致资源泄漏。

在非虚拟析构函数的情况下,将只调用基类的析构函数,如果派生类中存在未定义/未设置的基类成员,则会导致崩溃(尽管情况并非总是如此)

引用中提到的情况在多重继承的情况下是可能的,因为给定基类可能有不同的偏移量。从内存结构来看,继承的类包含在类中

 _____________________________
| Base class 1                |
 _____________________________
| Base class 2                |
|    .......                  |
 -----------------------------
在上述情况下,如果您试图使用基类2指针来删除或执行任何操作,您可能会遇到问题,除非您从对象地址获取偏移量。对于基类1指针,您不应该遇到任何问题

C++并没有将其隐式化,因为继承可能有不同的用途。此外,虚拟函数有性能损失。有时,人们不需要虚拟析构函数,因为基类只用于取出一些常见的东西,基类不用于引用对象(根据OOPs的概念,这可能是不正确的)C++也支持不同于其他语言的私有继承和受保护继承。使用派生对象作为基类没有任何意义。 不想使用虚函数的示例是私有继承,这意味着派生类是根据基类而不是基类来实现的。例如,堆栈可以使用数组来实现。您可以在堆栈中有一个数组对象,也可以私有地派生数组

class Stack: private Array {
  //Implement function using Array
}
显然,
Stack
在本例中不再是一个
Array
。因此,不需要在
Array
中使用虚拟析构函数。即使使用,由于私有继承,也无法释放
Stack
。 还有许多其他可能的情况

在您的情况下,您可能不会面临崩溃,但派生类的成员将无法获得自由,并导致资源泄漏

在基类没有虚方法的派生类中声明虚方法是错误的吗

不,这不是一个错误。它是安全的,只要您不使用错误的地址删除对象,这在场景中可能会发生

有人确切知道[亚伦·麦克戴德的断言]是否准确吗

是和否。确实“
Base*b=new-Derived();delete b;
将是未定义的行为,可能会使程序崩溃”

在某些系统上,对具体原因的解释是正确的,但该标准未指定虚拟分派的实现机制,该标准只规定了编译器编写者必须协调的行为。没有特别说明