C风格的强制转换在C++依然能用,但是C++鼓励程序员采用新风格的强制转换,即四种cast。const_cast主要用于处理const修饰,和其他几种有很大区别,因此不容易混淆。因此主要记录另外三种cast,不准确,但是便于记忆。
1. static_cast
普通的强制转换,基类<-->派生类,int <--> double等等。遵循C的隐式转换规则。
2. reinterpret_cast
最为接近C风格的强制转换,在static_cast基础上支持更宽松类型转换,比如可以把指针类型转换为int类型。
3. dynamic_cast
最为严格的强制转换,只能进行指针或者引用类型转换,而且要求满足转换安全。即只允许派生类类型向基类类型转换,否则抛出异常。
结合类的派生,考察以下程序
- #include <iostream>
- using namespace std;
- class base
- {
- public:
- base(){cout << "Construct Base\n";}
- virtual void print(){cout << "Base\n";}
- };
- class derive : public base
- {
- public:
- derive(){cout << "Construct Derive\n";}
- void print(){cout <<"derive\n"; }
- };
- int main()
- {
- derive dl;
- (static_cast<base> (dl)).print(); // "Base"
- (static_cast<base&> (dl)).print(); // "derive"
- derive * dp = new derive;
- //cout << (static_cast<int> (dp)); // 无法从“derive *”转换为“int”
- cout <<(reinterpret_cast<int>(dp)) << endl;
- (reinterpret_cast<base*> (dp))->print();
- delete dp;
- while(1);
- return 0;
- }
不难看出, static_cast是不能把指针类型转为整型,但是reinterpret_cast可以。我们可以理解为,reinterpret_cast是进行的内存级别的转换。
但是,其中有个蹊跷的地方,为什么static_cast做普通类型转换,调用的是基类的函数,难道是不查询虚表了吗?于是,我们进行下面的尝试:
- #include <iostream>
- using namespace std;
- class base
- {
- public:
- base(){cout << "Construct Base\n";}
- virtual void print(){cout << "Base\n";}
- };
- class derive : public base
- {
- public:
- derive(){cout << "Construct Derive\n";}
- void print(){cout <<"derive\n"; }
- };
- int main()
- {
- derive dl;
- cout << (reinterpret_cast <int> (&dl)) << endl;
- cout << reinterpret_cast <int> (& static_cast<base>(dl)) << endl;
- cout << reinterpret_cast <int> (& static_cast<base&> (dl)) << endl;
- while(1);
- return 0;
- }
执行结果:
- Construct Base
- Construct Derive
- 3079920
- 3079716
- 3079920
所以,虚表一样查询了,但是由于不是引用类型的转换,编译器重新生成了基类的实例。因此,查询的是基类的虚表而不是派生类的。
但是,这里生成的新实例,是按位复制的。那么是因为我们没有定义复制构造函数,还是编译器底层做的复制呢?给两个类添加复制构造函数,继续实验。
- #include <iostream>
- using namespace std;
- class base
- {
- public:
- base(){cout << "Construct Base\n";}
- base(const base& b){cout << "Copy construct\n";}
- virtual void print(){cout << "Base\n";}
- };
- class derive : public base
- {
- public:
- derive(){cout << "Construct Derive\n";}
- derive(const derive& d){cout << "Derive copy construct";}
- void print(){cout <<"derive\n"; }
- };
- int main()
- {
- derive dl;
- cout << (reinterpret_cast <int> (&dl)) << endl;
- cout << reinterpret_cast <int> (& static_cast<base>(dl)) << endl;
- cout << reinterpret_cast <int> (& static_cast<base&> (dl)) << endl;
- while(1);
- return 0;
- }
执行结果:
- Construct Base
- Construct Derive
- 1505236
- Copy construct
- 1505032
- 1505236
Bingo! 又让我猜中了,吼吼~因为是基类的对象,调用的只是基类的复制构造函数,把待类型转换的对象复制了一份基类的引用。
如果使用dynamic_cast就没有这么多问题了,因为只能转换指针和引用类型,不会构造新的对象。
转载于:https://blog.51cto.com/luckybins/995125