1.类封装 2.类继承 完成继承 覆盖继承 扩充继承 多重继承 在多重继承中,构造函数按照下列顺序进行调用: (1) 任何虚拟基类的构造函数按照它们被继承的顺序进行调用。 (2) 任何非虚拟基类的构造函数按照它们被继承的顺序进行调用。 (3) 任何成员变量的构造函数按照它们声明的顺序进行调用。 (4) 类自己的构造函数 在多重继承中,析构函数的调用顺序和构造函数的调用顺序相反。 规则1 可以用派生类对象为基类对象赋值。 Base b; Derived d; b=d; 规则2 可以用派生类对象初始化基类的引用。 Derived d; Base &b=d; 规则3 可以把派生类对象的地址赋给基类对象的指针。 Derived d; Base *p=&d; 规则4 可以把指向派生类对象的指针赋给基类对象的指针。 Derived *p; Base *fb=p; 3.类多态 C++中的多态性可以分为4类: (1)参数多态(模板) (2)重载多态 (3)包含多态(虚函数) (4)强制多态(自动类型转换) 《 重载、覆盖与隐藏》 1).重载:成员函数具有以下的特征时发生“重载” A.相同的范围(同一个类中) B.函数的名字相同 C.参数类型不同(不能进行隐式类型转换) D.Virtual关键字可有可无 2).覆盖(也叫“继承”):指派生类函数覆盖基类函数,特征是: A.不同的范围(分别位于基类与派生类中) B.函数名字相同 C.参数相同 D.基类函数必须有virtual关键字 3).隐藏:是指派生类的函数屏蔽了与其同名的基类函数,规则如下: A.如果派生类的函数与基类的函数同名,但是参数不同,此时不论有无virtual关键字,基类的函数都将被隐藏,注意别与重载混淆) B.如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时基类的函数被隐藏(注意别与覆盖混淆) 注:::如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数有virtual关键字,此时基类的函数没有被隐藏。可以通过child.Base::BaseFuntion()用继承类的对象来调用与基类同名同参的基类虚函数。 4.const: (1)成员变量 const修饰类的成员函数,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。 (2)成员函数 const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。 a. const成员函数不被允许修改它所在对象的任何一个数据成员。 b. const成员函数能够访问对象的const成员,而其他成员函数不可以。 注:用mutable修饰的非const数据成员是可以再const函数中修改的 (3)类对象 · const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。 · const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企 将Const类型转化为非Const类型的方法
采用const_cast 进行转换。 · 常量指针被转化成非常量指针,并且仍然指向原来的对象; · 常量引用被转换成非常量引用,并且仍然指向原来的对象; · 常量对象被转换成非常量对象。 5.static: (1)成员变量
(2)成员函数 与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。
(3)类对象 static对象如果出现在类中,那么该对象即使从未被使用到,它也会被构造以及析构。而函数中的static对象,如果该函数从未被调用,这个对象也就绝不会诞生,但是在函数每次被调用时检查对象是否需要诞生。 6.构造函数、析构函数 7.虚: (1)虚继承 为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。 ◇执行顺序 首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造; 执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造; 执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造; 执行派生类自己的构造函数; 析构以与构造相反的顺序执行; (1)虚函数:普通函数、构造、析构 1) 虚函数必须能且是公有继承 2)构造函数不能是虚函数 一,从存储空间角度 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如 果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable 呢?所以构造函数不能是虚函数。 二,从使用角度 虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例, 那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。 虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在 创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。 三、构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我 们可能通过实验室的基类的指针或引用去访问它 但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象 类型从而不能正确调用析构函数。 四、从实现上看,vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数 从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函 数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数 五、当一个构造函数被调用时,它做的首要的事情之一是初始化它的V P T R。因此,它只能知道它是“当前”类 的,而完全忽视这个对象后面是否还有继承者。 当编译器为这个构造函数产生代码时,它是为这个类的构造函数 产生代码- -既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。 3)基类的虚析构函数用来被派生类重写,释放派生类的资源 (2)虚继承 (3)虚表 8.(1)友元函数 (2)友元类 9.符号重载 10.模板 11.容器 12.命名空间 13.异常 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// C++相关的库:boost库、QT库、MFC、ACE
|
|