说一说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(指针常量),变成可以写的属性, 推荐使用在函数重载方向

因为

  1. 顶层const 形参与无顶层const 形参之间无法区分开
  2. 底层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:当你需要因为多个类型的不同而做不同的事情的时候,多个ifdynamic_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;
}