说一说c++中四种cast转换
C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast
static_cast:
static_cast: 任何具有明确定义的类型转换都可以使用static_cast进行转换,但是他无法去掉const性质
const char *cp;
char *q = static_cast<char *>(cp); // 错误
const_cast
const_cast :只能改变运算对象的底层const(指针常量),变成可以写的属性, 推荐使用在函数重载方向
因为
- 顶层const 形参与无顶层const 形参之间无法区分开
- 底层const 形参与无底层const 形参可以区分开
当对于一个非常量的对象,编译器会优先选择非常量的函数重载,在一个常量的函数与非常量函数之间。
在这种情况下,我们可以在这个非常量的函数内部通过const_cast 来调用常量的函数重载来实现非常量的函数重载。
reinterpret_cas
reinterpret_cast: 进行较低层次的重新解释,c语言风格的类型强制转换。
dynamic_cast
dynamic_cast: 用于将基类的指针或引用安全的转换成派生类的指针或引用。来进行运行时类型识别,当然该类型需要含有虚函数。
从而可以用来识别同一父类的不同子类。根据转换完是否为nullptr,或catch异常来识别。(指针==>nullptr, 引用是抛出异常)
当然为了动态识别运行时类别,也可以使用visitor 模式来完成运行时类型识别。
dynamic_cast同visitor 模式相比的话,
这两种方法互有利弊,而且利弊是完全相反的。dynamic_cast
的做法扩展新的类容易,扩展新的逻辑困难。
而 visitor 模式的做法,扩展新的类困难,扩展新的逻辑容易。
dynamic_cast
的好处:
- A:代码写起来直接。
- B:每次添加新的子类,这个类和关于它的一组不同的逻辑,可以通过抽取函数来组织到同一个文件里。
dynamic_cast
的坏处:
- C:当你需要因为多个类型的不同而做不同的事情的时候,多个
if
和dynamic_cast
会导致性能低下(虽然其实不是很严重),代码结构也会相当混乱。 - D:当你添加一个新的子类的时候,你要找到所有需要添加新分支的
if
,哪怕你测试足够,也很容易出错。 - E:添加关于所有类的一个新逻辑的时候,你又要写一大堆
if
,不仅混乱,而且编译器还无法查漏补缺,很容易犯错误。
visitor 模式的好处:
- C:因为这毕竟是一个O(1)跳转,不同的类只需要跳转一次就可以运行相应的函数(而不是用
if
一个一个尝试),性能高。 - D:当你添加一个新的子类的时候,只要你 visitor 接口的成员都是纯虚类,你很容易通过阅读所有编译错误来找出所有需要修改。
- E:添加关于所有的类的一个新的逻辑很容易,就是继承自接口,井井有条。
visitor 模式的坏处:
- A:代码写起来比较曲折。
- B:每次添加新的子类,都会修改很多相关的文件。但是在编译器的编译错误的帮助下,其实这并不是一个令人恐怖的问题,只是看起来恐怖。
visitor 模式实例
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;
class Cat;
class Dog;
class Mouse;
class IAnimalVisitor {
public:
virtual void Visit(Cat *animal) = 0;
virtual void Visit(Dog *animal) = 0;
virtual void Visit(Mouse *animal) = 0;
};
class Animal
{
private:
string name;
public:
Animal(const string& theName)
:name{
theName }
{
}
virtual ~Animal()
{
}
const string& GetName()const
{
return name;
}
virtual string Introduce()const = 0;
virtual void Accept(IAnimalVisitor* visitor) = 0;
};
class Cat : public Animal
{
public:
Cat(const string& theName)
:Animal{
theName }
{
}
string Introduce()const override
{
return "我是一只猫,我的名字叫\"" + GetName() + "\"。";
}
virtual void Accept(IAnimalVisitor* visitor) {
visitor->Visit(this);
}
};
class Dog : public Animal
{
public:
Dog(const string& theName)
:Animal{
theName }
{
}
string Introduce()const override
{
return "我是一只狗,我的名字叫\"" + GetName() + "\"。";
}
virtual void Accept(IAnimalVisitor* visitor) {
visitor->Visit(this);
}
};
class Mouse : public Animal
{
public:
Mouse(const string& theName)
:Animal{
theName }
{
}
string Introduce()const override
{
return "我是一只老鼠,我的名字叫\"" + GetName() + "\"。";
}
virtual void Accept(IAnimalVisitor* visitor) {
visitor->Visit(this);
}
};
class IntroduceForCatVisitor : public IAnimalVisitor {
public:
virtual void Visit(Cat *animal) {
cout << animal->Introduce() << endl;
}
virtual void Visit(Dog *animal) {
}
virtual void Visit(Mouse *animal) {
}
};
int main()
{
auto tom = make_shared<Cat>("Tom");
auto jerry = make_shared<Mouse>("Jerry");
auto spike = make_shared<Dog>("Spike");
auto butch = make_shared<Cat>("Butch");
auto lightning = make_shared<Cat>("Lightning");
vector<shared_ptr<Animal>> friends{
tom, jerry, spike, butch, lightning };
IntroduceForCatVisitor visitor;
for (auto animal : friends)
{
animal->Accept(&visitor);
}
return 0;
}