1. 面向对象的三个特征
封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
多态:是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有二种方式,覆盖,重载。覆盖,是指子类重新定义父类的虚函数的做法。重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
2. static_cast、dynamic_cast、reintepret_cast、cont_cast有什么不同?为什么需要多种不同的转换风格?
在看这些转换之前先来了解一下C风格的转换:
隐式转换:
short a = 2000; int b; b = a; //隐式转换
显式转换:
double a = 2000.3; short b; b = (short) a; // c-like cast notation b = short(a); // functional notation
这种显式转换方式简单直观,但并不安全!
ok,下面我们来看看上述的各种转换方式:
1)static_cast 静态转换 用法:static_cast<type_id> (expression)
静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。但其实 static_cast 已经有安全性的考虑了,比如对于不相关类指针之间的转换。
下面对比一下C风格转换与static_cast转换
// class type-casting #include <iostream> using namespace std; class CDummy { float i,j; public: CDummy(float x, float y) { i = x; j = y; } }; class CAddition { int x,y; public: CAddition (int a, int b) { x=a; y=b; } int result() { return x+y;} }; int main () { CDummy d(5, 10); CAddition *padd; padd = (CAddition*) &d; cout << padd->result()<<endl; return 0; }
此时,两个不相关的类指针之间的转换是成功的,编译器也没有提示Warning!但是,在 static_cast 是不允许转换的,因此可以看出 static_cast 有自身的安全机制!
padd = static_cast<CAddition*>(&d);
error: invalid static_cast from type ‘CDummy*’ to type ‘CAddition*’
总结一下:static_cast最接近于C风格转换了,但在无关类的类指针之间转换上,有安全性的提升。
2)dynamic_cast 动态转换 用法:dynamic_cast<type_id> (expression)
dynamic_cast 运算符可以在执行期决定真正的类型。如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。
如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的;
在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。
3)reintepret_cast 强制类型转换符 用法:reinterpret_cast<type-id> (expression)
这和 C 的显式转换有点类似,例如,对于两个毫无相关的类之间的转换也是成功的!
class CDummy { float i,j; public: CDummy(float x, float y) { i = x; j = y; } }; class CAddition { int x,y; public: CAddition (int a, int b) { x=a; y=b; } int result() { return x+y;} }; int main () { CDummy d(5, 10); CAddition *padd; //padd = static_cast<CAddition*>(&d); padd = reinterpret_cast<CAddition*>(&d); cout << padd->result()<<endl; //int pointer to int int *i = new int(100); int y = reinterpret_cast<int>(i); cout<<"y = "<<y<<endl; //int to int pointer int *c = NULL; c = reinterpret_cast<int*>(y); cout<<"*d = "<<*c<<endl; //equal to *i return 0; }
结果输出:
$ ./cast -2118123520 y = 161939464 *d = 100
总结:reinterpret_cast 是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)
static_cast 和 reinterpret_cast 的区别主要在于多重继承,比如
class A { public: int m_a; }; class B { public: int m_b; }; class C : public A, public B {}; C c; printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为 static_cast 计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。
因此, 你需要谨慎使用 reinterpret_cast.
总结:
1. static_cast
对于内建类型的转换
会出现溢出情况,需要程序员自身去判断转换是否安全
对于单继承的转换
class A{}; class B: public A {};
B=>A 允许 没有类型检查
A=>B 不允许
对于多继承的转换
class A{}; class B{}; class C: public A, public B {};
A=>C 不允许
B=>C 不允许
C=>A 允许
C=>B 允许
对于无相关类之间的转换
class A{}; class B{};
A=>B 不允许
B=>A 不允许
是否能够改变被转换者的const volatile __unaligned属性
不能
2. dynamic_cast
对于内建类型的转换
int a = dynamic_cast<int>(double d); //ERROR
double d = dynamic_cast<double>(int i); //ERROR
对于单继承的转换
class A{}; class B: public A {};
B=>A 允许 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
A=>B 不允许
对于多继承的转换
class A{}; class B{}; class C: public A, public B {};
A=>C 不允许
B=>C 不允许
C=>A 允许
C=>B 允许
对于无相关类之间的转换
class A{}; class B{};
A=>B 不允许
B=>A 不允许
是否能够改变被转换者的const volatile __unaligned属性
不能
3. reinterpret_cast
对于内建类型的转换
int a = reinterpret_cast<int>(double d); //ERROR
double d = reinterpret_cast<double>(int i); //ERROR
对于单继承的转换
class A{}; class B: public A {};
B=>A
A=>B
对于多继承的转换
class A{}; class B{}; class C: public A, public B {};
A=>C
B=>C
C=>A
C=>B
对于无相关类之间的转换
class A{}; class B{};
A=>B 允许 这是需要注意的。
B=>A 允许 这是需要注意的。
是否能够改变被转换者的const volatile __unaligned属性
不能
4. const_cast
C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力;static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性;dynamic_cast要求转换类型必须是指针或引用,且在下行转换时要求基类是多态的,如果发现下行转换不安全,dynamic_cast返回一个null指针,dynamic_cast总是认为void*之间的转换是安全的;reinterpret_cast可以对无关类指针进行转换,甚至可以直接将整型值转成指针,这种转换是底层的,有较强的平台依赖性,可移植性差;const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。
五. typedef 的作用
typedef通常被用于以下三种目的:
- 为了隐藏特定类型的实现,强调使用类型的目的;
- 简化复杂的类型定义,使其更易于理解;typedef QList<EntityCustomer> CustomerLst;
- 允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。