如果从析构函数调用纯虚函数是UB,为什么可以使用纯虚析构函数?
If call to a pure virtual function from destructor is UB, why can we use pure virtual desrtuctors?
可以使用纯虚析构函数,如下所示:
struct A {
virtual ~A() = 0;
};
A::~A() {}
struct B : A {};
因为标准规定在10.4 [class.abstract] p2
纯虚函数只有在调用时才需要定义…With (12.4 [class. doctor])
之后在12.4 [class.dtor] p9
析构函数可以声明为虚函数(10.3)或纯虚函数(10.4);如果在程序中创建了该类的任何对象或任何派生类,则应定义析构函数。
这意味着上面的代码是完全有效的——A::~A
可能是纯虚的,它是定义的,B::~B
隐式调用A::~A
。
到目前为止,一切顺利。
然后我读到10.4 [class.abstract] p6
:
成员函数可以从抽象类的构造函数(或析构函数)调用;直接或间接地对纯虚函数进行虚调用(10.3),对于从这样的构造函数(或析构函数)创建(或销毁)的对象,其效果是未定义的。
但这正是我们在这里所做的——我们从析构函数调用纯虚函数A::~A
。
所以,这不是某种矛盾吗?
没有收缩
从B
的析构函数调用A
的虚析构函数。A
的析构函数不是B
的成员。
标准§9.3
成员函数
在类定义中声明的函数,不包括那些用友元说明符声明(
类的成员函数
标准规定,当从抽象类析构函数/构造函数(在您的例子中,将是类A
)向其自己的纯虚成员函数之一进行虚调用时,存在未定义的行为。
[…成员函数可以从抽象类的构造函数(或析构函数)中调用[…];
你的引言说对于析构函数:
- 可以从抽象类的析构函数中调用成员函数
- 如果你从同一个抽象类的析构函数中调用纯虚方法,则存在未定义行为。
如果存在虚拟调用 (10.3 [class.virtual]),则会发生UB。
对纯虚函数进行虚调用(10.3)的效果…是未定义的。
但10.3[类。虚拟]p15说
作用域操作符(5.1)的显式限定抑制了虚调用机制。
似乎隐式析构函数调用具有显式限定条件。
至少编译器不会做虚调用
相关文章:
- 为什么可以将左值传递给"std::async",即使它引用了右值
- 为什么可以修改数组 b?
- 为什么可以将整数分配给字符串变量?
- 为什么可以在头文件中定义类?
- 为什么可以将 std::unique_ptr* u1 <A>作为 u1[1000] 访问并且它仍然有效
- 是否可以使C++类成为Objc类的委托
- 为什么可以重复使用这个boost::asio::tcp::socket
- 将变量定义为静态时,为什么可以多次定义它
- C++:为什么可以在没有事先使用 new 的情况下在指向结构的指针上使用 delete?
- 是否可以使一个类成为两个不同层次结构的子类?
- 为什么可以通过常量左值引用传递右值?
- 为什么可以进行此任务?
- 为什么可以使用已删除的移动构造函数和赋值运算符移动对象?
- 为什么可以将左值传递到采用常量引用右值的构造函数中?
- 为什么可以在没有实例变量的情况下访问静态回调方法中的静态成员变量?
- 为什么C++可以使用派生结构来实例化其父模板结构,而父模板可以调用子结构的函数?
- 为什么C++可以使用未初始化的成员变量(引用或指针 *NOT 值复制*)来初始化其父类的成员变量
- 为什么可以添加填充使您的循环更快
- 为什么我可以使protected方法在后继程序中公开
- 为什么可以给引用赋一个新值,以及如何使引用引用其他东西