1、理解C和C++的区别
在C中,数据和处理数据的方法是分开声明的,没有关联,这就是程序性的方法。二者不仅是风格上的不同,封装性多态性等的存在会使c++更具威力。虽然使用起来更复杂一些。
2、加上封装的成本
很多人会觉得c++加上封装成为类之后,会增加很多成本。但其实并不会这样,因为类中声明的成员函数不会出现在对象实体中,每个成员函数只有一个函数实体。(内联函数除外)
C++在布局和存取时间上的负担主要产生在以下两个方面:
1、虚函数机制,用于实现多态,运行期绑定;
2、虚基类。用于实现多次出现在继承体系中的基类只有一个单一共享的实体。
另外,多重继承也会有一些负担,但是多重继承并不常用。
3、C++对象模型
在C++对象模型中,
非静态成员变量放在每一个对象之内;
静态成员变量则放在对象之外,因为他是属于类的;
所有成员函数放在对象之外;
对于虚函数,我们用以下两步实现:
每个对象产生一堆指向虚函数的指针,这些指针放在一个表格中,每个指针指向一个虚函数,称为vtbl;
每个对象内还会增加一个指向虚函数表格的指针,称为vptr.它的设定和重置都是由构造函数,析构函数,复制运算符等自动完成的,对我们来说是透明的。
所以在对象中,我们有非静态成员变量和一个vptr;
这个模型的优点在于:空间和存取时间效率。缺点是如果应用程序代码没变,但是对象的非静态数据成员变了,代码会重新编译。因为非静态数据成员是放在对象内的。
那么还有一个问题,虚拟继承如何实现?
我们需要思考,在继承中,派生类在本质上是如何模塑其基类实体的。
如果我们在派生类对象增加一个指向基类对象的指针,那么必然会因为继承层数增加,额外空间用于存放指针,且存取时间大。
在C++最初时期,不采用任何的间接性,基类的data直接置于派生类对象中。这提供了对基类对象的最紧凑,有效率的存取。
但是有一个致命缺点,基类的任何改变,派生类对象都必须重新编译。
自从C++2.0导入了虚基类,我们需要一些间接的基类表现方法。最原始的就是在对象中为关联的虚基类加上一个指针,其他演化出来的模型无非就是导入一个虚基类表或者扩充原来的虚函数表,具体我们后面会说。
程序设计典范
三种,程序模型,抽象数据类型,面向对象模型。我们最好使用一种典范编写程序,使程序更加健壮。
现在,我们只说面向对象模型。对于实现多态来说,简单来说,尽量使用对象的指针和引用来处理。举个例子:
如果我们有library父类和book子类。
library thing1;
book b;
thing1=b;
这是典型的抽象数据类型典范。这时thing1中只包含book中基类的部分,被切割了。
正确的方法是:
library &thing2;或者指针形式
thing2=book.这时就是完整的book类型了。调用的也是子类中的函数。
C++中提供三种方法实现多态:
1.隐含的转换操作,比如让派生类的指针指向基类指针shape *ps=new circle()
2、虚函数机制;
3.dynamic_cast和typeid运算符;
指针的类型:
int *p1;
float *p2;
book *p3;
指针类型不同不在于其中地址不同,在于寻址出的内容不同。它指导编译器如何解释寻址的内容和大小。
比如:一个指向1000位置的int指针,在32位机器下,将涵盖1000-1003四个字节的空间。
比如cast(转型)的编译器指令,就是改变其寻址内容和大小,不改变指针包含的地址。