1.C++是强类型语言,一般编译器会检查出不适合的转型操作。
2.类型转换的形式:
- 旧式转型(两种方式本质相同):
- C风格:(T)expression。
- 函数风格:T(expression)。
- 新式风格(或C++风格):
- const_cast<T>(expression):去除表达式的常量性,是C++中唯一能做此操作的转型操作符。
- dynamic_cast<T>(expression):主要用来执行“安全向下转型”,即用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
- reinterpret_cast<T>(expression):试图执行低级转型(例如将一个指向整数变量的指针转换为整数),实际动作及结果可能与编译器相关,因而降低了可移植性。
- static_cast<T>(expression):隐式转换。注意虽然可以使非const类型转换为const,但反之不能。
如果必须要转型,尽量使用新式风格,它们更容易识别,也更容易被编译器纠错。
3.如果一个类具有一个或多个单个参数的构造函数,则该类支持隐式类型转换:如果有必要,它可以在接受该参数类型的对象后自动将其转换为该类类型。
但是,除非有明显的理由想要定义隐式转换,否则,单形参的构造函数应该声明为explicit(在函数声明前加上explicit关键字,但是不要在类外的定义上再加此关键字)。这样类型转换就必须是显式调用的。
P118的例子里,使用显式类型转换也不是必须的,最好还是构造一个对象。
4.以一个基类指针指向派生类对象,如果基类不是虚基类,则会造成隐式的类型转换(P118的例子):对象从派生类转化为基类,从而造成“地址偏移”。由于各个编译器对内存的布局处理不尽相同,因而如果程序中使用了这种“布局处理”,可能会降低可移植性。
5.很多应用框架会要求派生类中的虚函数先调用基类中的同名函数,如:
class Window{
public:
virtual void onResize(){...}
...
};
...
class SpecialWindow : public Window{
public:
virtual void onResize(){
static_cast<Window>(*this).onResize(); //试图将“当前对象”转换为基类类型的对象并调用基类的同名函数
... //这里进行该函数区别于基类同名函数的特定行为
}
...
};
以上的调用并不是调用当前对象的函数,而是稍早转型动作所建立的“*this对象的基类部分“的暂时副本上的onResize()函数,意即:它先在“当前对象的基类成分”的副本上调用了基类的onResize()函数,然后在当前对象上执行了区别于基类函数的特定行为。因而,如果基类的onResize()函数改变成员变量的值,则它在派生类中的执行是无效的。
应当将相应的代码修改为:
class SpecialWindow : public Window{
public:
virtual void onResize(){
Window::onResize(); //调用Window::onResize()作用于*this身上
...
}
...
};
6.dynamic_cast执行速度很慢,应避免使用。考虑这样一个情形:想在派生类对象上执行派生类的操作函数,但只有一个指向基类的指针或引用,可以采用两种方法加以避免:
(1)使用容器并在其中存储直接指向派生类对象的指针。(PS:意思可能是:原先那个基类指针干脆不用了,自己建立智能指针去。呃,怎么觉得作者有些无聊……)
(2)在基类内提供虚函数,使用多态。(PS:这是相当大路货的东西了,没想到竟然到这里才讲。)
7总之,转型总是应当避免的;当实在无法避免的时候,就把转型操作隔离在函数中,以方便维护。