引用

dynamic_cast<type>()
动态转换只支持方法多态类型的指针,如果转换成功返回指针,失败则返回nullptr
同样分为两种情况:

  1. 向下转换 downcast
  2. 跨类转换 crosscast

注:不要随便转换this指针

还有一点,当dynamic_cast用于转换引用时,转换失败会抛出异常,所以一般不推荐转换引用


正文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class father{
public:
};

class son :public father{
public:
};

class wolf :public son{
};

class pople :public son{
};

class werewolf :public wolf, public pople{
};

还是之前的例子

1
2
3
4
son s1;
father* fh = (father *)&s1;

son *s2 = static_cast<son *>(fh);

正常情况下我们知道静态转换可以这么操作。

1
2
3
4
son s1;
father* fh = (father *)&s1;
fh = new father();
son *s2 = static_cast<son *>(fh);

虽然强转,但是毕竟父类和子类结构不一样,指针的时候不是很理想。

1
son *s2 = dynamic_cast<son *>(fh);

用动态转换的时候他要求类是一个多态类,那么在基类中加一个虚函数

1
2
3
4
5
6
class father{
public:
virtual void test(){

}
};

然后编译就能通过了,对此是否完成转换,前面提到过转换成功返回指针,没成功返回nullptr。

显然是失败了,因为fh指针我们重新new了一个father类型。导致和son不同。

1
2
3
4
5
6
7
son s1;
father* fh = (father *)&s1;
//fh = new father();
son *s2 = dynamic_cast<son *>(fh);

if (s2 == nullptr) std::cout << "error!\n";
else std::cout << "success!\n";

当我们注释掉重新new的那句,fh仍然指向一个son类型的,那么它的指针信息就会和son有关。


不要过度依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class father{
public:
virtual void test(){}
};

class son :public father{
public:
void Move(){

}
};

class daughter :public father{
public:
void Move(){

}
};

然后无脑为了转换基类指针,然后调用各自的move

1
2
3
4
5
auto sp = dynamic_cast<son *>(fh);
auto du = dynamic_cast<daughter *>(fh);

if (sp != nullptr) sp->Move();
if (du != nullptr) du->Move();

这些全是下饭操作,这其实没有必要去做什么动态转换,直接在基类里面加一个虚函数,子类重写一下直接调用是最快的。

不可取


不要乱玩this指针

1
2
3
4
5
6
7
class father{
public:
virtual void test(){}
virtual void Move(){
if(dynamic_cast<father*>(this))
}
};

假设基类中有虚函数,它对this指针进行了一些操作,那么当派生类继承下来的时候,就全是在派生类上动手脚了,虽然语法规定没有限制不能转换this指针,但是不推荐这么操作,大多情况下人都把握不住。


强转指针和引用

之前说为了保证数据的完整,建议都是通过指针或者引用转换。

1
2
3
son s1;
father* fh = (father *)&s1;
father &fh1 = (father &)s1;

这两种强转都是没有什么问题的,引用本身就是弱化的指针。

而当使用dynamic_cast的时候,也是前面提到过的问题。

1
2
son *s2 = dynamic_cast<son *>(fh);
daughter &au = dynamic_cast<daughter &>(s1);

dynamic_cast去做引用的转换时,他如果出错了不是返回nullptr而是抛出异常。

在底层上,指针存在空指针,而引用没有空引用的说法。


跨类转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class father{
public:
virtual void test(){}
virtual void Move(){
//if(dynamic_cast<father*>(this))
}
};

class son :public father{
public:
void Move(){

}
};

class daughter :public father{
public:
void Move(){

}
};

class wolf :public son{

};

class pople :public son{

};

class Box{};

class werewolf :public wolf, public Box{

};

构建一个新类box,他跟father之类的毫无关系,但是他被werewolf继承。

那么这个类还适合转换吗?

1
2
werewolf wf;
father *fa = (father *)&wf;

因为存在多重继承,向下继承的适合自己推敲有点麻烦,就看看动态能不能直接完成。

1
auto p = dynamic_cast<Box *>(fa);

显然是可以的。

他是成功返回了一个指针,而不是nullptr。

那么在关联上

father和box是没有直接关系的,但是werewolf继承了这两个,因此包含了他俩的属性,所以werewolf可以主动转换成father和box类型。


结语

迷迷糊糊。