一篇文章入门C++

3,328 阅读17分钟

为什么要学习C++:

       抛开C++在一些物联网,高性能引擎(游戏等)及各种操作系统等行业使用的专业性,不论作为java开发还是其他开发,我们的知识体系里面必不可少的定有操作系统相关的知识,而关于操作系统,如果我们想要更深入的了解的话,看懂它的一些代码当然是必不可少的。再或者,开发一些高性能的工具或者组件,这些,都离不开C和C++,而对于C++的学习其实就基本上已经学会了C的一些东西(如果以前没有接触过C的话),基于二八法则,基本已够用。

C++语言的由来:

       1982年,美国AT&T公司贝尔实验室的Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)博士在C语言的基础上引入并扩充了面向对象的概念,从而创造了C++这门程序语言,也叫做带类的C(c with class)。Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)博士也被尊称为C++语言之父。

推荐c++学习开发工具

  windows上使用vc即可,mac上使用xcode即可
强烈推荐使用Qt creator 学习开发,也可以学习下Qt库

C++语法

认识C++的对象:

C++的函数和对象:

  • 注释方式(基本与java注释类似)
/*....*/  
//.... 
  • 输入输出流
    cin和cout是C++语言中进行输入输出操作的函数,定义在istream头文件中。
    例子:
cout << "" << endl;  //c代表c系语言,out代表输出,endl代表换行 
  • 使用命名空间 命名空间是C++语言中封装程序库名称的一种机制
    C++ 标准类库中的对象和函数都属于std命名空间,使用这些函数和对象时要using namespace std
    #include "iostream" //包含头文件
    #include "cmath"
    using namespace std
    
    • 使用std命名空间时注意:
      使用c语言中的头文件时,要写成“xxx.h”形式
      使用c++中的头文件则不能加上“.h”
      命名空间可自定义,可嵌套,比如小王定义的是A命名空间,小李定义的是B命名空间,就算他们的函数重名了,一摸一样了也没事,可以通过命名空间::函数名来调用。
  • 对象的定义及初始化
    c语言:int x; x=0; 等价于 int x=0;
    c++ 语言(等价于上两条c语句):int x(0); 此种初始化语法在c++中称为构造函数语法
  • 函数原型及其返回值
    函数要有类型,若要得到处理结果则要使用return语句(与java类似,其实java的面世很多都是参考c++)。
    例子: int result(int a,int b){ int d; d = a+b; return d; }
    函数调用在函数定义之前时要对函数进行声明
    例子: int result(int a,int b); //进行函数声明 void main(){ //主函数 ... z = result(x ,y); //调用定义的函数 ... } int result(int a,int b){ //定义函数 int d; d = a+b; return d; }
  • const修饰符和预处理程序
    常量定义:(在c语言中是这样定义的,注意c++语法包含容纳c语法,c++就像是对c的一个扩充) #define PI 3.1415
    (在c++中是这样定义的) 在变量定义之前加上const关键字,类似java,表示定义的变量值不可改变。 const int PI = 3.1415; (第一种)
    const int PI(3.1415); (第二种,即构造函数语法)
    利用const定义常量时必须给出常量的值,除非该常量是extern(外部变量、即全局变量)的。 以#开始,分为宏定义,文件包含和条件编译。
  • 程序的书写规则
    注意缩进对齐,区分大小写,类似java,有所不同。

C++语言面向过程编程的特点

  • 函数重载
    (与java类似)C++允许一个函数定义多个版本,使得一个函数完成多种功能,即同一个函数名定义多次。
    例子:

     int max(float a,float b){
      return a > b ? a:b;
     }
     
     int max(int a,int b,int c){
     int d;
     d = a > b ? a:b;
     return d > c ? d:c;
     }
     int max(int a,int b){
      return a>b ? a:b;
     }
    

    如例子所示,重载函数的特点:
    函数名相同,参数个数不同,或者参数类型不同。

  • C++的数据类型(包括java等,几乎所有有语言的数据类型都囊括这些)
    1.void类型
    void表示空类型,或者无类型,表示函数无返回值。

    2.bool类型(逻辑型,布尔型)
    占1个字节,表示逻辑运算符中的 真 、假。

    3.整型(int、 long、 short)
    int、short至少16位
    long至少32位
    short不得比int长 int 不得比long长

    4.char型(字符型)
    占1个字节。

    5.实型(float/double/long double) 我们可以通过sizeof来观察这些数据类型的长度
    例子:

     cout << sizeof(bool) << endl;
     cout << sizeof(int) << endl;
     cout << sizeof(short) << endl;
     cout << sizeof(long) << endl;
     cout << sizeof(char)  << endl;
     cout << sizeof(float) << endl;
     ......
    

    6.&取地址符(取某一个变量的地址) 例子:

    int x;
    int *p;  //p是指针变量,指针变量能存放变量的地址
    p = &x; //&x表示取出变量x的地址,p = &x表示将变量x的地址取出后存入指针变量p
    

    7.常量表示
    整型: 0前缀表示8进制数,0x前缀表示16进制数,加L、I后缀表示长整型常量
    实型: F、f后缀表示浮点型常量(float);
    实数加L、I后缀表示long double类型;
    无前缀、无后缀的为double类型;

  • 动态分配内存
    new动态分配内存
    一般格式: 指针变量 = new 类型[size];
    new 运算符得到新分配空间的首地址、赋值给指针变量后,可根据指针变量的加减运算来使用这些空间。 (与java不同,java有垃圾回收机制,自动释放内存,而c++是没有的) delete 释放内存,使用完毕后要释放内存。
    delete p;

  • 引用的使用方法
    引用即使用变量的别名。
    定义形式:数据类型 & 别名 = 对象名;
    作用:别名与对象名对应同一个对象,共用同一段内存。对别名的修改会造成原对象的修改。
    例子: int x; int & a = x; //a是变量x的别名,a和x完全等价
    使用别名时的注意事项:
    1.不能定义引用的引用,如错误示范: int & &r=x;
    2.不能直接定义数组的引用

使用typedef定义某类型的别名   
一般格式:typedef 类型 类型别名  
例子:
```  
typedef long int lint; 
//long int i;
lint i; //lint i 等价于 long int i
```
  • 对指针使用const限定符
    1.左值和右值
    表达式:E1 = E2 ; E1是左值,是可被修改的;
    int *p,x = 1; *p = 2; &p表示指针p的地址
    2.指向常量的指针和常量指针
    const常量定义:表示const后的表达式不可改变,定义时必须给出表达式的值。
    例子: int x = 11; const int *p; //错误写法,必须初始化 const int *p = &x; //错误写法,*p是不能在=的左边 int * const p = &x; //正确写法(注意:p不可改变,但是*p可变)

3.指向常量的常量指针  
例子:
``` 
int x = 11;
const int * const p = &x; //表示p不可变,*p也是不可变的
```   
  • 泛型算法应用于普通数组
    泛型算法是C++标准模版库(Standard Template Library)提供的一组操作。利用这些操作可以简化数组操作。 要使用这些操作必须包含头文件<algorithm>
    假定a,b是两个数组名,其长度为len 例子: reverse(a,a+len); //将数组a中的元素顺序反转(逆向),注意,len需要替换成长度,比如len=5,则len应该换成5 copy(a,a+len,b); //将a数组的内容原样复制给b数组 reverse_copy(a,a+len,b); //将a数组的内容反转后复制给b数组 sort(a,a+len) ;//将数组a中的元素按升序排序 sort(a,a+len,greater<type>()) ;//将数组a中的元素按降序排序,type是数据类型,比如type是int,应该将type替换成int find(a,a+len,value);//在数组a中查找值为vavlue的元素,并返回位置指针 copy(a,a+len,Ostream_iterator<type>(cout,"分隔字符串")); //Ostream_iterator表示输出流操作符,<type>表示要输出的数组类型,cout表示流输出操作,“分隔字符串”即就是分隔字符的

  • 程序的编辑、翻译、运行
    程序从无到有为编辑,出来的c++源代码
    对比C和C++文件的各种后缀(由于历史原因,可谓花样真多,现在只展示统一的):

    语言头文件源文件
    c.h.c
    c++.h,但是openCV采用 .hppwindows平台 .cpp,linux平台 .cc
    源码进行编译为翻译
            c++的编译器有不少,其中熟知的有MSVC、GCC、Cygwin、MingW(Cygwin和MingW的英文发音),另外还有些 小众和新秀,像ICC(Intel C/C++ Compiler)、BCC(Borland C/C++ Compiler,快销声匿迹了)、RVCT (ARM的汇编/C/C++编译器,内置在ARM的IDE——RVDS中)、Pgi编译器……

    我们在linux下最常用的:
    GCC原名GNU C Compiler,后来逐渐支持更多的语言编译(C++、Fortran、Pascal、Objective-C、 Java、Ada、Go等),所以变成了GNU Compiler Collection(GNU编译器套装),是一套由GNU工程开发的支 持多种编程语言的编译器。GCC是自由软件发展过程中的著名例子,由自由软件基金会以GPL协议发布,是大多数类 Unix(如Linux、BSD、Mac OS X等)的标准编译器,而且适用于Windows(借助其他移植项目实现的,比如 MingW、Cygwin等)。GCC支持多种计算机体系芯片,如x86、ARM,并已移植到其他多种硬件平台.
    有时候,在linxu中下载一些第三方工具,提示我们需要下载相关gcc依赖等,就是因为这个工具由于c++开发,需要使用gcc进行编译才可执行使用。

执行即为c++编译后的文件,进行汇编和链接后的执行

从结构到类的演变:

结构的演化:

  • 结构发生质的演变
    1.函数与数据共存
    c++允许结构中定义的函数,成为成员函数。在结构中同时定义成员变量和成员函数。
    使用格式:
    结构对象.成员变量
    结构对象.成员函数
    例子:
    ``` #include //引入头文件 io using namespace std; //使用c++标准类库中的类,需要使用std命名空间 struct point{ //point即为结构名,结构是c++中的一种数据结构,类似类 double x,y; void updatexy(double a, double b){ x = a; y = b; }

    void display(){ cout << x << "\t" << y << endl; //endl是换行的意思 } }; //注意结构数据定义完后要有分号

void main(){
 point p; //表示定义了p,与java不一样的是,这个p已经包含了java中= new .. 后面的动作,所以可直接调用p
 p.updatexy(1.5,1.7);
 p.display();
 cout << p.x << "\t" << p.y << endl;
}
```

2.封装
如果定义结构体时,使用了private关键字,则产生封装性。 例子:

struct point{
 private: //这里区别于java,可以只写一个private,所有private的放在其下
  double x,y;  //这时候,在main中,通过point的变量名直接 . 变量,就不行了
 public:  //区别于java,可以只写一个public....
  void updatexy(double a,double b){
   x = a;
   y = b;
  }
  void display(){
  cout << a << "\t" << b << endl;
  }  
};

在定义结构时,如果使用了private则产生封装性,表示成员为私有的,只能在结构体内部通过公有成员函数使用。如果未添加private,则表示默认为public。值得注意的是类在定义时默认却为private。

  • 使用构造函数初始化结构的对象
    在定义结构时,与结构同名的函数称为构造函数。
    如果定义的函数与某个已定义函数重名而参数类型或者个数不同,则称为函数重载。
    例子:
struct point{
private:
  double x,y;
public:
  point(){};
  point(doube a,double b){
   x = a;
   y = b;
  }
  void updatexy(....){ ... } 
  .....
}

与java的类类似,构造函数在定义结构体对象时自动执行,并根据是否初始化来自动选择所调用的构造函数。
这里需要区分的是:java的对象定义,在定义后,如果不new对象,它的变量名对应的对象则为null(这个null需要我们给赋给其),如果new对象的话,不仅会创建一个对象,还会自动进行初始化,也就是java的对象创建流程里面已经包含了初始化。但是c++则不一样,(c++也有new对象的方式,new出来的为动态对象)c++定义好后,就已经有这个对象了,但是初始化的过程由我们来控制,可以调用有参数的构造函数,那在对象定义完成后,也已经完成了初始化过程。

结构演化成一个简单的类:

将结构的struct替换为class即变为类的标准定义形式。 例子:

class point{
 private:
   double x,y;
 public:
   point(){};
   point(double a,double b){
   x = a;
   y = b;
   };  
   void updatexy(double a,double b){
   x = a;
   y = b;
   }
   void display(){
    cout << a << "\t" << b << endl;
   }   
};

类图的表示(UML即统一建模语言等):

point
-x : double
-y : double
+point()
+updatexy()

+display()
其中,point为类名,x,y为类属性(成员变量),point和updatexy、display为类操作(成员函数)。

面向过程和面向对象:

直观的从一道题来区分:
给出两点坐标,计算亮点间距,并输出。
1.面向过程的求解步骤 :
步骤:
+ 输入x1,y1,x2,y2 四个数据
计算(x1,y1)和 (x2,y2)的距离
输出计算出的距离
2.面向对象的求解步骤
+ 设计类
将点设计为一个类,并提供相关的属性和操作
定义对象同时给出坐标
point A(x1,y1)
point B(x2,y2)
定义对象,然后获取坐标
计算距离并输出

C++面向对象程序设计特点

  • 对象
    三要素:对象名,属性,操作

使用类和对象

  • 使用类和对象
    1.使用string对象
string
- str
+string()
+find()

+size()
+substr
该类是c++语言中的内部预定义类,要在程序中使用该类时必须添加头文件 #include <string> ;

**注意:**头文件引入的两种写法,#include <...> 和 #include "..." 。

类的初始化:string str1 = "A";
string str1("hello "); string str2 = "world";
与java类似,string对象允许使用 + 运算
* 使用complex对象
complex类用于定义一个复数对象,使用时添加头文件 #include <comlex>
定义格式:complex <int> num1(1,2);
* 使用对象总结
使用标准类库中的类时,必须添加头文件。
定义对象方式同变量定义方式类似。
定义对象时可对对象进行初始化。
同类的不同对象由对象属性来区分。
不同类的对象具有不同的成员函数可实现不同操作。
类是具有相同特征和操作的对象的抽象。

函数和函数模版

函数的参数及其传递方式

c语言中参数传递方式只有一种:值传递(值传递分为变量值传递和变量地址值传递)。
c++中分为:值传递和地址传递(引用传递),与java类似。 参数不同传递形式:对象作参数,对象指针作参数,对象引用作参数。
引用的声明形式:
数据类型 &别名 = 对象名; int x = 21;
int &a = x;
引用对象不是一个对立对象,与原对象同用一个地址空间,不占用内存。
对象的指针作参数时,指针变量中存放实参对象的地址。

函数的返回值

与java类似,但是多了指针类型。

内联函数

定义函数时,加inline关键字表示该函数为内联函数。
例子:

inline int wheatherNumber(char c){
 return c > '0' && c < '9' ? 1:0;
}

程序中的内联函数在程序编译时,将函数替换至程序中函数调用位置,造成程序变长,效率提高。
注意事项: 内联函数中不能出现循环、switch语句等
内联函数一般短小,不宜过长
应在调用之前声明或定义

函数模版

有些函数重载时参数个数相同,只是类型不同,此时重载函数比较繁琐,可利用函数模版实现。
例子:

template <class type>  
type max(type a , type b){
  return a > b ? a:b;
}

void main(){
  int x = 1,y = 2;
  double x1 = 1.2,y = 2.1;
  
  int z;
  double z1;
  
  z = max(x,y);
  z1 = max(x1,y1);
  cout << "最大值:int类型为 " << z << "  dobule类型为  " << z1 <<endl;

}

定义函数模版后,函数调用时根据函数参数类型来确定调用哪个版本的函数。函数执行时确定参数类型的函数称为模版函数。

类和对象

类及其实例化

  • 类的定义
    例子模版: ``` class 类名{ private: //私有的数据成员和成员函数 public: //公有的数据成员和成员函数 protected: //保护的数据成员和成员函数 };

    void 类名::函数名(){

    }

```  

:: 称为域限定符,表示函数是类的成员函数。在类外使用域限定符定义函数,若想定义为内联,加inline关键字就即可。
类内定义的函数默认为内联函数。

  • 使用类的对象
    类的对象的使用类似变量的使用。
    声明/定义对象,直接利用对象名使用,通过对对象的引用使用对象,通过指向对象的指针使用对象。
  • 数据封装
    与结构体封装类似

构造函数

  • 默认构造函数
    若类的定义中未定义构造函数,则c++编译器会自动产生一个不带参数的默认构造函数,类似于:point(){},此时不对对象进行初始化。若类中定义了构造函数,则不再产生默认构造函数。

  • 定义构造函数
    构造函数无返回值,这样可以减少编译器的工作,提高效率。
    构造函数与类同名。
    构造函数可以重载。
    构造函数系统自动调用。

  • 构造函数和运算符new
    new 和构造函数一同起作用,即new首先给对象分配内存,然后自动调用构造函数来初始化这块内存。 例子:
    ``` void main(){

    Point *ptr = new Point; Point *ptr1 = new Point(1,2); delete ptr; delete ptr1; } ```
    new建立的动态对象只能用delete删除,并会释放空间。

  • 复制构造函数
    <类名>::<复制初始化构造函数>(const 类名 &引用名)

析构函数

           析构函数的调用由编译器自动调用,析构函数名在类名前加~,析构函数无返回值,析构函数无参数,可以显示说明为void,析构函数不可以重载,析构函数在对象生命周期结束的时候由系统自动调用。

  • 定义析构函数
    例子:

    class Point{
     private:
            int x,y;
     public :
            Point(const Point&);
            Point(int a = 10,int b = 10);
            ~Point();
       
    }
       ……
    

    类的对象组的每个元素调用一次构造函数,调用一次析构函数。
    全局对象数组的析构函数在程序结束之前会被调用。

  • 析构函数和运算符delete
    delete后自动调用析构函数。与new 相反。

  • 默认析构函数
    编译器为没有析构函数的类自动产生一个空体析构函数,与构造函数类似。 分配几次内存调用几次构造函数,释放几次内存,调用几次析构函数。

this指针

       this指针是c++实现粉状的一种机制,它将对象和该对象调用的成员函数连接在一起。this指针保证了每个对象可以拥有自己的数据成员。(跟java类似) 例子:

Point::Point(int a=0,int b=0){
 this->x=a;
 this->y=b;
}
point::Point(const Point &p){
  this->x=p.x;
  this->y=p.y;
}

类和对象的性质

  • 对象的性质
    1.同一类的对象之间可以互相赋值; 2.可以使用对象数组; 3.可以使用指向对象的指针; 4.对象可以用作函数参数; 5.对象作为函数参数时,可以使用对象、对象引用和对象指针; 6.一个对象可以用作另一个类的成员。
  • 类的性质
    1.使用类的权限 2.不完全的类声明
    只有当使用类产生的对象时,才进行内存分配。
    类没有完全定义之前就引用该类。
    不完全声明仅用于类和结构
    3.空类
    4.类作用域
    类中默认控制权限是private

面向对象编程的文件规范

  • 编译指令
  • 在头文件中使用条件编译
    #if ...

特殊函数和成员

静态成员

成员定义时使用static关键字
1.静态成员变量的初始化只能在类外进行。
2.类中的任何成员函数都可以访问静态成员变量。
3.访问静态成员时,一般加上类名限定。
4.静态成员变量是类的成员,不是对象的成 员。 5.对象未建立之前静态成员已经存在。
6.静态成员没有this指针,除非使用引用方式,否则不能存取类的成员。(与java类似,但是比java强大)
静态成员包括静态对象。

友元函数

可以实现两个类之间无限制的存取另一个类的成员。
友元函数可以访问私有成员,公有成员和保护成员。友元函数可以是一个类或函数。友元需要通过对象来使用类的成员。
友元的三种形式:
1.普通函数作为一个类的友元
例子:

  class Point{
  
     double x,y;
   public:
      Point(double x1,double y1){x = x1, y =y1}
      friend double max(Point & p1,Point & p2);
  };
  
  double max(Point &p1,Point &p2){  //注意,此函数为Point类的友元函数,与其成员函数有区别
    return p1.x+p1.y > p2.x+p2.y ? p1.x+p1.y : p2.x+p2.y; 
  }

2.a类的成员函数作为b类的友元
例子:

 class A{
   private:
      int x;
   public:
      A(int a){x = a;}
      int getX(){return x;}
      void fun(B & t);
 };
 
 class B{
  private:
     int y;
  public:
     B(int b){y = b;}
     int getY(){return y;}
     friend void A::fun(B & t);
 };
 
 void A::fun(B & t){
   t.y = x;
 }

3.a类作为b类的友元

  class B{
  
   private:
      int y;
   public:
      B(int b){y = b;}
      int getY(){return y;}
      friend class A;
  }

const对象

const 可限定变量、指针、对象 函数、数据成员、成员函数。便是不可改变。
const对象只能调用const成员函数 例子:

 class circle{
   private:
     double r;
     const double PI;
     static int count;
   public:
     circle(double a):PI(3.14159265354){ //此即为const成员函数的定义方式
      r = a;
      count = count+1;
     }
 
 }

main函数

main函数为入口函数,与java类似,但是只能有一个main

继承和派生

继承和派生的基本概念

继承关系是类与类之间的类属关系(从概念上来说,与Java类似,但是java只支持单一继承) 类的继承是指:派生类继承基类的所有数据成员和成员函数。用于表示类之间的类属关系,非构成关系。
派生类的特点:
1.增加新成员。
2.重定义已有成员函数。
3.改变基类的成员的访问权限。

单一继承

  • 一般形式
     class 派生类名:访问控制 基类名{
       private:
          成员列表;
       public:
          成员列表;       
       protected:
          成员列表;   
     }
    
  • 派生类的构造函数和析构函数
    派生类中继承的基类的成员初始化时,需要由派生类的构造函数调用基类的构造函数。 派生类的构造函数一般形式: 派生类名::派生类名(参数):基类名(参数){ //函数体 }
    构造函数和析构函数不能被继承。
  • 类的保护成员protected
    派生类使用基类的私有成员,保持封装性,可以将私有限定改为protected(与java类似)
  • 访问权限
  • 赋值兼容规则
  • isa和has-a的区别
    isa关系:继承和派生关系。
    has-a关系:一个类使用另一个类的对象作成员。
    公有继承关系一般和isa关系是等价的。
  • 公有继承存取权限表
基类派生类基类对象派生类对象
private不可访问不可访问不可访问
publicpublic可访问可访问
protectedprotected不可访问不可访问
  • 私有派生
    定义派生时,用private限定 。基类的公有成员和保护成员变为私有成员。

  • 保护派生
    定义派生时,用proetcted限定 。 降级使用,基类中的private变为不可访问,protect变为private,public变为protected。

多重继承

一般形式(java只能单一继承,c++可以多重继承):
class 类1:访问控制 lei2,访问控制 类3{
private: //私有成员 protected: //保护成员 public: //公有成员
}

二义性及其支配原则

  • 作用域和成员名限定
    当派生类中从多个基类中继承得到同名函数时,在派生类中使用这些函数时,须使用类名限定!派生类的对象使用这些函数时,也需要进行类名限定!

  • 派生类支配基类的同名函数
    在基类和派生类有重名的成员时,优先派生类的成员,如果要访问基类成员,必须加上左右域符号 ::
    私有成员派生类不可访问,只有本类和友类可以访问
    如果派生类要访问基类的成员,基类成员应该用protected限定。

类模版与向量

类模版

  • 类模版的基础知识
    template<class T> class 类名{
     .....
    }
    
类模版的对象:类名<模版参数> 对象名(参数); 
模版类的成员函数定义形式: 
template<class T> 返回值类型 类名<T>::函数名(参数){
  //函数体
}
  • 类模版的派生与继承
    模版类继承普通类,模版类作普通类的派生类。
    继承后成员使用与一般类的继承成员使用一样。
    模版类派生模版类。
    模版类使用时,须指出模版类参数。

向量与泛型算法

  • 定义向量列表
    向量是c++中一维数组的类版本,用于存放多个相同类型的数据。
    可以动态指定向量中元素的个数。可以使用泛型算法。(可类比java中的集合) 向量的声明形式:
    vector <类型> 向量名;
    vector <类型> 向量名(长度);
    vector <类型> 向量名(长度,a);
    vector <类型> 向量名1(向量名2);
    vector <类型> 向量名(a,a+长度);
    以上所说的a是数组名。

  • 向量的数据类型
    向量不仅可存取int,double等普通数据类型,也可以存储对象,指针,对象的指针。

  • 向量的基本操作方法
    类比数组,以及使用泛型算法。

多态性和虚函数

多态性

  • 赋值兼容规则是指在需要基类对象的du任何地方都可以使用zhi公有派生类的对象来替代。通过公有dao继承,派生类得到了基类中除构造函数、析构函数之外的所有成员,而且所有成员的访问控制属性也和基类完全相同。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。赋值兼容规则中所指的替代包括以下的情况:

   1.派生类的对象可以赋值给基类对象。

   2.派生类的对象可以初始化基类的引用。

   3.派生类对象的地址可以赋给指向基类的指针。

  • 静态联编中的赋值兼容性和名字支配规律。
    类的对象和调用的函数一一对应,程序编译时即可确定对象调用哪个函数,称为静态联编。
    通过指针调用成员函数时:所调用成员函数为指针所属类的成员函数,即有赋值兼容规则决定指针调用的成员函数
  • 动态联编的多态性
    要实现程序运行时决定指针所调用的函数是基类的还是派生类的,即:动态联编。可以利用虚函数实现动态联编。

虚函数

  • 虚函数的格式:
    virtual double area(){ return 0; } 虚函数不能是静态成员。

  • 虚函数实现多态性
    使用虚函数实现多态的三个前提:
    1.类之间的继承关系满足赋值兼容性规则;
    2.改写了同名虚函数; 3.根据赋值兼容性规则使用指针(或引用)。

  • 构造函数和析构函数调用虚函数
    标准c++不支持虚构造函数 ,支持虚析构函数。

  • 纯虚函数与抽象类
    1.纯虚函数的格式
    class 类名{ virtual 函数类型 函数名(参数列表)=0; }
    2.抽象类
    包含纯虚函数的类称为抽象类
    抽象类的派生类如果没有实现抽象类中的全部纯虚函数,这个派生类依旧是抽象类。
    纯虚函数与空的虚函数是不同的:
    1.virtual void area()=0; //纯 2.virtual vodi area(){} //空

多重继承与虚函数

首先,多重继承是多个单一继承的集合。

类成员函数的指针与多态性

在派生类中,当一个指向基类成员函数的指针指向一个虚函数,并且通过指向对象的基类指针(或引用)访问这个虚函数时,会发生多态性。

运算符重载和流类库

运算符重载

  • 重载对象的赋值运算符

  • 运算符重载的实现

  • << >> 和 ++ 运算符重载的实例
    例子:

      //插入符函数的一般形式
     ostream &operator<<(ostream& output,类名& 对象名){
        return output;
     }
    
  • 类运算符和友元运算符的区别

  • 下标运算符 “[ ]”的重载

流类库

  • 流类库的基础类
    把接收输出数据的地方叫做 目标
    把输入数据来自的地方叫做 源头