1、构造函数和析构函数linux
对象的构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,而后调用成员对象的构造函数。析构则严格按照与构造相反的次序执行,该次序是惟一的,不然编译器将没法自动执行析构过程。安全
一个有趣的现象是,成员对象初始化的次序彻底不受它们在初始化表中次序的影响, 只由成员对象在类中声明的次序决定。这是由于类的声明是惟一的,而类的构造函数能够有多个,所以会有多个不一样次序的初始化表。若是成员对象按照初始化表的次序进行构造,这将致使析构函数没法获得惟一的逆序。函数
最好把基类的析构函数声明为虚函数。这将使全部派生类的析构函数自动成为虚函数。这样,若是程序中显式地用了delete运算符准备删除一个对象,而delete运算符的操做对象用了指向派生类对象的基类指针,则系统会调用相应类的析构函数。ui
2、虚继承this
虚继承是多重继承中特有的概念。虚基类是为解决多重继承而出现的。如:类D继承自类B一、B2,而类B一、B2都继承自类A,所以在类D中两次出现类A中的变量和函数。为了节省内存空间,能够将B一、B2对A的继承定义为虚继承,而A就成了虚基类。指针
class A对象
class B1:public virtual A;继承
class B2:public virtual A;内存
class D:public B1,public B2;资源
3、多态
一、存在虚函数的类都有一个一维的虚函数表叫作虚表。类的对象有一个指向虚表开始的虚指针(指针在64位机器上占8个字节)。虚表是和类对应的,虚表指针是和对象对应的。
二、在构造函数中进行虚表的建立和虚表指针的初始化。
三、虚表能够继承,若是子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。若是基类有3个虚函数,那么基类的虚表中就有三项(虚函数地址),派生类也会有虚表,至少有三项,若是重写了相应的虚函数,那么 虚表中的地址就会改变,指向自身的虚函数实现。若是派生类有本身的虚函数,那么虚表中就会添加该项。
四、派生类的虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。
五、虚表的一个很差的地方是,既然知道的虚指针,就能够根据地址调用相关的虚函数,即便该虚函数是私有的(linux平台是这样的)。
4、static
静态数据成员:
1) 一个类中能够有一个或多个静态成员变量,全部的对象都共享这些静态成员变量,均可以引用它。
2) static 成员变量和普通 static 变量同样,编译时在静态数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的建立而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象建立时分配内存,在对象销毁时释放内存。
3) 静态成员变量必须初始化,并且只能在类体外进行,不用加访问权限控制符private,public等。例如:
int Student::num = 10;
初始化时能够赋初值,也能够不赋值。若是不赋值,那么会被默认初始化,通常是 0。静态数据区的变量都有默认的初始值,而动态数据区(堆区、栈区)的变量默认是垃圾值。
4) 静态成员变量既能够经过对象名访问,也能够经过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。当经过对象名访问时,对于不一样的对象,访问的是同一分内存。
静态成员函数
静态成员函数和静态数据成员同样,它们都属于类的静态成员,它们都不是对象成员。所以,对静态成员的引用不须要用对象名。
静态成员函数与非静态成员函数的根本区别是:非静态成员函数有 this 指针,而静态成员函数没有 this 指针。由此决定了静态成员函数不能访问本类中的非静态成员,只能访问静态数据成员。
5、const
const限定符的做用就是限定一个变量的值不能改变(由于有的时候咱们但愿一个变量的值不被改变)。为了这个蛋疼的功能,给C++添加了不少复杂性。
一、初始化:因为const变量的值定了之后不能再改变,因此规定const必须(显式)初始化。const变量的初始化和变量的初始化同样,由于从语义上来讲,只是变量赋初值而已。
因为编译期间,编译器可能会把程序中const变量替换成其值,因此每一个文件的const变量都应该初始化即定义。为了支持这一用过,const变量是默认只在本文件内有效。能够经过extern实现一处实现,多处声明,这样编译器就不会进行值替换。
const数据成员的初始化只能在类的构造函数的初始化列表中进行。但static const类型的初始化仍是在类外初始化。
二、const引用:表示该引用不会改变其绑定的变量的值。const引用和引用的初始化略有不一样:引用初始化时要求引用类型和变量类型严格一致,
但const引用绑定的对象能够是非const变量(从语义上来讲所绑定的对象是否是const对const引用可有可无)或变量的类型能够转换成引用的类型。
由于在引用初始化的类型转换中,会先产生一个临时量,而后引用绑定的是这个临时量。这个临时量是const的,因此非const引用不能绑定该临时量,可是const引用能够。编译器为了增长引用的使用范围作了一些工做,使const引用看起来使用范围更广。
三、const和指针:常量指针表示指针自己是const,指向常量的指针表示指向的变量是个常量。指针赋值,包括const指针初始化,仍是主要看所指向的变量类型是否一致(能够进行类型转化)。
最后,非const引用和非指向const类型的指针不能绑定和指向const变量,const引用和指向const类型的指针能够绑定和指向非const变量。(缘由很好理解)
6、引用和指针
一、引用即便别名,因此引用定义时必须有一个显式的对象。引用的类型要与所绑定的类型严格匹配,一些const引用的状况除外。
引用的底层实现仍是指针,经过编译器编译后的汇编代码能够看出。即编译过程当中,遇到引用都是变成对引用所绑定对象的地址的操做,因此没有引用这个变量即引用不是变量。
指针是变量,存放的地址。经过->(成员选择运算符)能够操做指定地址的内存(或 解引用和.运算符)。
二、指针和引用的区别:一、指针能够从新赋值或者进行别的运算,而引用不能够(有点像常量指针* const p)。二、引用必须初始化,而指针能够默认初始化(这也有可能出现未定义的状况)。三、引用的做用就是更加符合人们的使用习惯,并且必定程度上确保操做的安全(不会出现指针操做失误引发的野指针等状况,与指针相比)。四、“sizeof 引用”获得的是所指向的变量(对象)的大小,而“sizeof 指针”获得的是指针自己(所指向的变量或对象的地址)的大小。
7、智能指针
一、 智能指针是利用RAII(在对象的构造函数中执行资源的获取(指针的初始化),在析构函数中释放(delete 指针):这种技法把它称之为RAII(Resource Acquisition Is Initialization:资源获取即初始化))来管理资源。利用的是栈对象的生存周期。
二、解决的问题是new了一个对象,可是忘记delete或者在未delete以前,程序出现异常,致使对象没有释放。
(1)auto_ptr,头文件<memory>C++11提供了更多的智能指针,可是在此以前只有auto_ptr。可是auto_ptr存在的最大的问题是不能共享全部权,能够转移全部权,即:
auto_ptr<string> p1(new string("test"));
auto_ptr<string> p2;
p2 = p1;
p1的指针为NULL,p2的指针指向new string。若是再使用p1,就会形成程序崩溃。在容器中常常有赋值操做,因此,auto_ptr不能用于容器。可是进行简单的释放对象操做仍是能够的,可是要当心使用。
不能使用C++11,可使用boost库来解决这些问题。
(2)scoped_ptr,头文件<boost::scoped_ptr.hpp>,与auto_ptr相似,可是不能进行全部权的转移。上述代码中,若是使用的是boost::scoped_ptr,则p2 = p1;这条语句,编译器不会经过。由于boost::scoped_ptr的赋值运算符是私有的。
若是能够的话尽可能用scoped_ptr来代替auto_ptr。
(3)shared_ptr,头文件<boost::shared_ptr.hpp>,它维护了一个引用计数器,可以共享全部权,当引用计数器为0时,才释放对象。这样shared_ptr能够用于STL容器。
因此,要用于容器,或者多个智能指针要指向同一个对象,选择shared_ptr。
但维护引用计数器,确定要有一些消耗,简单的替代delete做用,可用scoped_ptr或者auto_ptr。
9、extern “C”
在C++环境下使用C函数的时候,经常会出现编译器没法找到obj模块中的C函数定义,从而致使连接失败的状况,应该如何解决这种状况呢?
答案与分析: C++语言在编译的时候为了解决函数的重载问题,在生成汇编代码时会将函数名与参数(或者返回值)联合起来生成一个中间的函数名称,而C语言则不会,所以会形成连接时找不到对应函数的状况。此时对引用的C函数须要用extern “C”修饰,这告诉编译器,请保持个人名称,用C的方式处理函数名。