跟进类似的问题以前的帖子关于向下转换和类型安全,不知下面的示例创建未定义的行为。
已创建 Base 类的实例。不会发生动态绑定。
但是,在 Base::interface 函数中, Base 类的实例被转换为 Derived 类的实例。这安全吗?如果是,为什么?请在下面找到一段代码。
#include <iostream>
template <typename Derived>
struct Base{
void interface(){
static_cast<Derived*>(this)->implementation();
}
};
struct Derived1: Base<Derived1>{
void implementation(){
std::cout << "Implementation Derived1" << std::endl;
}
};
int main(){
std::cout << std::endl;
Base<Derived1> d1;
d1.interface();
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
没有Derived这个 newDerived *可以指向,所以它绝对不安全:演员本身具有未定义的行为,如 [expr.static.cast]§11(强调我的)中所述:
类型为“指向cv1 的 指针”的纯右值
B,其中B是类类型,可以转换为类型为“指向cv2 的 指针”的纯右值D,其中D是从 派生的完整类B,如果cv2与 cv 限定相同或更高cv-资格比,cv1。[...]如果“指向cv1 的 指针B”类型的纯右值指向B实际上是类型对象的子对象的 aD,则结果指针指向类型为封闭对象的对象D。否则,行为是 undefined。
您可以通过限制对Base的构造函数的访问来降低这种风险:
template <typename Derived>
struct Base{
// Same as before...
protected:
Base() = default;
};
Run Code Online (Sandbox Code Playgroud)
这更好,但如果有人不小心定义了struct Derived2 : Base<AnotherDerived> { };. 可以通过特定friend声明来防止这种情况发生,但缺点是可以完全访问Base的私有成员:
template <typename Derived>
struct Base{
// Same as before...
private:
friend Derived;
Base() = default;
};
Run Code Online (Sandbox Code Playgroud)
请注意,这仍然允许在其成员函数中Derived构造裸体Base<Derived>对象,但这就是我通常停止敲打鼹鼠的地方。
| 归档时间: |
|
| 查看次数: |
49 次 |
| 最近记录: |