静态转换工作和动态转换段错误
static cast working and dynamic cast segfaults
以下代码可以编译并正常工作:
#include<iostream>
class Base {
protected:
int _a;
public:
virtual ~Base()=default;
Base(int a) : _a{a} {};
int getit() const { return _a; }
};
class Derived : public Base {
public:
Derived(int a) : Base{a} {};
int get2() const { return 2*this->_a; }
};
int main() {
Base D{2};
auto* ptr = &D;
auto* ptr2 = static_cast<Derived*>(ptr);
std::cout << ptr2->get2() << std::endl;
}
输出
4
如果我将 static_cast
更改为 dynamic_cast
它会出现段错误。
我的问题:
使用 static_cast
转换为不添加任何数据成员的派生 类 是否安全?
Is it safe to use static_cast to cast down to derived classes
仅当对象的动态类型是派生的 class(或者派生的 class 是进一步派生的动态类型的基础时)。向上转换也是安全的,但这种转换也是隐式的。
如果您不知道情况是否如此,并且 - 如示例中那样 - 当您知道情况并非如此时,这绝对是不安全的,并且示例程序的行为是未定义的。使用 dynamic_cast
是安全的,但不检查它是否 returns 为 null,然后通过该 null 进行间接访问是不安全的。
总之,这是安全的:
if (auto* ptr2 = dynamic_cast<Derived*>(ptr)) {
std::cout << ptr2->get2() << std::endl;
} else {
std::cout << "It's not Derived :(" << std::endl;
}
也就是说,如果您认为需要 dynamic_cast
,那么您可能应该重新考虑设计。您可能应该改用虚函数。示例:
class Base {
protected:
int _a;
public:
virtual ~Base()=default;
Base(int a) : _a{a} {};
virtual int getit() const { return _a; }
};
class Derived : public Base {
public:
using Base::Base;
int getit() const override { return 2*this->_a; }
};
在这种情况下,使用错误类型的演员会让您感到悲伤。如评论中所述,ptr2
未指向有效的 Derived
对象。
因此,对于您的 static_cast
,您看到了未定义的行为;这恰好给出了一个明显的 'correct' 答案,但你永远不能依赖它。
但是,使用 dynamic_cast
将导致 ptr2
具有 nullptr
值(因为 ptr
指向的对象不是 Derived
);您试图取消引用 nullptr
导致您的程序崩溃(通常会崩溃)。
但请注意,使用 dynamic_cast
可以让您轻松检查转换是否成功(通过测试 nullptr
的返回值); static_cast
没有给你那个选项。
以下代码可以编译并正常工作:
#include<iostream>
class Base {
protected:
int _a;
public:
virtual ~Base()=default;
Base(int a) : _a{a} {};
int getit() const { return _a; }
};
class Derived : public Base {
public:
Derived(int a) : Base{a} {};
int get2() const { return 2*this->_a; }
};
int main() {
Base D{2};
auto* ptr = &D;
auto* ptr2 = static_cast<Derived*>(ptr);
std::cout << ptr2->get2() << std::endl;
}
输出
4
如果我将 static_cast
更改为 dynamic_cast
它会出现段错误。
我的问题:
使用 static_cast
转换为不添加任何数据成员的派生 类 是否安全?
Is it safe to use static_cast to cast down to derived classes
仅当对象的动态类型是派生的 class(或者派生的 class 是进一步派生的动态类型的基础时)。向上转换也是安全的,但这种转换也是隐式的。
如果您不知道情况是否如此,并且 - 如示例中那样 - 当您知道情况并非如此时,这绝对是不安全的,并且示例程序的行为是未定义的。使用 dynamic_cast
是安全的,但不检查它是否 returns 为 null,然后通过该 null 进行间接访问是不安全的。
总之,这是安全的:
if (auto* ptr2 = dynamic_cast<Derived*>(ptr)) {
std::cout << ptr2->get2() << std::endl;
} else {
std::cout << "It's not Derived :(" << std::endl;
}
也就是说,如果您认为需要 dynamic_cast
,那么您可能应该重新考虑设计。您可能应该改用虚函数。示例:
class Base {
protected:
int _a;
public:
virtual ~Base()=default;
Base(int a) : _a{a} {};
virtual int getit() const { return _a; }
};
class Derived : public Base {
public:
using Base::Base;
int getit() const override { return 2*this->_a; }
};
在这种情况下,使用错误类型的演员会让您感到悲伤。如评论中所述,ptr2
未指向有效的 Derived
对象。
因此,对于您的 static_cast
,您看到了未定义的行为;这恰好给出了一个明显的 'correct' 答案,但你永远不能依赖它。
但是,使用 dynamic_cast
将导致 ptr2
具有 nullptr
值(因为 ptr
指向的对象不是 Derived
);您试图取消引用 nullptr
导致您的程序崩溃(通常会崩溃)。
但请注意,使用 dynamic_cast
可以让您轻松检查转换是否成功(通过测试 nullptr
的返回值); static_cast
没有给你那个选项。