如果将对象创建为引用,为什么即使基类析构函数不是虚拟的,也会调用派生类析构函数
Why derived class destructor called even though base class destructor is not virtual if object is created as reference
#include <iostream>
class Database
{
public:
Database()
{
std::clog << "Database object created " <<std::endl ;
}
~Database()
{
std::clog << "Database object destroyed " << std::endl;
}
virtual void Open(const std::string & ) = 0 ;
} ;
class SqlServer : public Database
{
public:
void Open(const std::string & conn)
{
std::clog << "Attempting to open the connection "<< std::endl ;
}
~SqlServer()
{
std::clog << "SqlServer:Database object destroyed "<< std::endl ;
}
} ;
int main()
{
Database &ref = SqlServer();
ref.Open("uid=user;pwd=default");
return 0 ;
}
输出
已创建数据库对象
尝试打开连接
SqlServer:数据库对象已销毁//为什么这被称为析构函数在数据库中不是虚拟
的数据库对象已销毁
注意:如果我用 pref 替换 ref,那么一切正常,即 sqlserver 析构函数不会被调用。
这是
的?涉及对临时const
引用的特殊情况。临时的析构函数被正确调用,而不是引用的析构函数,因为毕竟临时的生存期只是延长了。
类似于安德烈·亚历山德雷斯库在他的瞄准镜后卫中使用的技巧。不过,他使用了一个const
的临时引用。
根据C++标准,使用临时值初始化的引用会使该临时值在引用本身的生存期内有效。
临时变量的寿命与引用一样长,当它被销毁时,将调用正确的析构函数。
来自通用:永远改变你编写异常安全代码的方式
<小时 />在为什么派生类的析构函数是在对基类的常量引用上调用
您正在将临时绑定到引用。通常这是不允许的,但 MSVC 有一个允许它的邪恶扩展。您可以通过声明const Database &ref = SqlServer();
并注释掉ref.Open()
行在其他编译器中重现这一点,因为临时可能受 const 引用的约束。
因此,对于 MSVC 中的原始代码或其他编译器中的修改代码,您看到的记录的析构函数消息来自临时销毁的消息。引用使临时保持活动状态,当引用超出范围时,临时引用也会超出范围。
Database &ref = SqlServer();
ref
绑定到临时引用,您可以使用 VS 扩展绑定到 const 引用,但最好不要使用它,这些扩展是邪恶的。建议使用智能指针。
class Database
{
public:
Database()
{
std::clog << "Database object created " <<std::endl ;
}
~Database()
{
std::clog << "Database object destroyed " << std::endl;
}
virtual void Open(const std::string & ) = 0 ;
virtual ~Database() {}
} ;
std::unique_ptr<Database> conn(new SqlServer());
conn->Open("uid=user;pwd=default");
注意:数据库类用作基类,但尚未定义virtual destructor
。如果通过指向的指针删除派生类型的对象,则会得到未定义的行为基地。
相关文章:
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 是否可以使用函数指针调用虚拟析构函数?
- 在没有动态内存的世界中,我是否需要虚拟析构函数?
- "虚拟""覆盖"析构函数
- 程序永远不会进入虚拟析构函数
- C++ std::vector 中的虚拟析构函数继承
- 哪种方法更适合处理虚拟析构函数?
- 拥有"受保护的非虚拟析构函数"与"受保护虚拟析构构函数"有什么好处
- 带有未解析外部元素的C++虚拟析构函数
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- 从内部类的析构函数调用虚拟函数
- C++切片和虚拟析构函数
- C++虚拟继承、虚拟析构函数和 dynamic_cast<void*>
- 添加虚拟析构函数会使代码大小膨胀
- 应该是虚拟析构函数吗?但是怎么做呢?
- 虚拟析构函数将对象移出 rodata 部分
- 为什么虚拟类的析构函数不会自动添加到 vtable 中?
- 如何将 std::unique_ptr<Parent> 与具有受保护虚拟析构函数的只读父类一起使用
- DIRECTX9 中自定义顶点的虚拟析构函数
- 声明析构函数虚拟就足够了吗?