分享

C++重点基础知识

 海漩涡 2014-05-03
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.参数类型不同(不能进行隐式类型转换)

DVirtual关键字可有可无

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 进行转换。  
用法:const_cast <type_id>  (expression) 
该运算符用来修改类型的constvolatile属性。除了const volatile修饰之外, type_idexpression的类型是一样的。

·             常量指针被转化成非常量指针,并且仍然指向原来的对象;

·             常量引用被转换成非常量引用,并且仍然指向原来的对象;

·             常量对象被转换成非常量对象。


5.static:
    (1)成员变量
         
  • 对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;
  • 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
  • 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
  • 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
    <数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问形式:
    <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
    如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
  • 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;
  • 同全局变量相比,使用静态数据成员有两个优势:
  1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  2. 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;
   
     (2)成员函数
         与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。

       
  • 出现在类体外的函数定义不能指定关键字static;
  • 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
  • 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
  • 静态成员函数不能访问非静态成员函数和非静态数据成员;
  • 由于没有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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多