为什么要学习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注释类似)

arduino复制代码/..../
//....

输入输出流
cin和cout是C++语言中进行输入输出操作的函数,定义在istream头文件中。
例子:

bash复制代码cout << "" << endl; //c代表c系语言,out代表输出,endl代表换行

使用命名空间
命名空间是C++语言中封装程序库名称的一种机制
C++ 标准类库中的对象和函数都属于std命名空间,使用这些函数和对象时要using namespace std
arduino复制代码#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++允许一个函数定义多个版本,使得一个函数完成多种功能,即同一个函数名定义多次。
例子:
css复制代码 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来观察这些数据类型的长度
例子:
c复制代码 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.&取地址符(取某一个变量的地址)
例子:
css复制代码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.不能直接定义数组的引用

arduino复制代码使用typedef定义某类型的别名

arduino复制代码一般格式: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.指向常量的常量指针

ini复制代码例子:

int x = 11;
const int * const p = &x; //表示p不可变,*p也是不可变的

泛型算法应用于普通数组
泛型算法是C++标准模版库(Standard Template Library)提供的一组操作。利用这些操作可以简化数组操作。
要使用这些操作必须包含头文件
假定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()) ;//将数组a中的元素按降序排序,type是数据类型,比如type是int,应该将type替换成int find(a,a+len,value);//在数组a中查找值为vavlue的元素,并返回位置指针 copy(a,a+len,Ostream_iterator(cout,"分隔字符串")); //Ostream_iterator表示输出流操作符,表示要输出的数组类型,cout表示流输出操作,“分隔字符串”即就是分隔字符的

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

语言头文件源文件c.h.cc++.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是换行的意思
}
}; //注意结构数据定义完后要有分号


csharp复制代码void main(){

css复制代码 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关键字,则产生封装性。
例子:
csharp复制代码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。

使用构造函数初始化结构的对象
在定义结构时,与结构同名的函数称为构造函数。
如果定义的函数与某个已定义函数重名而参数类型或者个数不同,则称为函数重载。
例子:

ini复制代码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即变为类的标准定义形式。
例子:
ini复制代码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
**注意:**头文件引入的两种写法,#include <...> 和 #include "..." 。
类的初始化:string str1 = "A";
string str1("hello ");
string str2 = "world";
与java类似,string对象允许使用 + 运算

  • 使用complex对象
    complex类用于定义一个复数对象,使用时添加头文件 #include
    定义格式:complex num1(1,2);
  • 使用对象总结
    使用标准类库中的类时,必须添加头文件。
    定义对象方式同变量定义方式类似。
    定义对象时可对对象进行初始化。
    同类的不同对象由对象属性来区分。
    不同类的对象具有不同的成员函数可实现不同操作。
    类是具有相同特征和操作的对象的抽象。
    函数和函数模版
    函数的参数及其传递方式
    c语言中参数传递方式只有一种:值传递(值传递分为变量值传递和变量地址值传递)。
    c++中分为:值传递和地址传递(引用传递),与java类似。
    参数不同传递形式:对象作参数,对象指针作参数,对象引用作参数。
    引用的声明形式:
    数据类型 &别名 = 对象名;
    int x = 21;
    int &a = x;
    引用对象不是一个对立对象,与原对象同用一个地址空间,不占用内存。
    对象的指针作参数时,指针变量中存放实参对象的地址。
    函数的返回值
    与java类似,但是多了指针类型。
    内联函数
    定义函数时,加inline关键字表示该函数为内联函数。
    例子:
    arduino复制代码inline int wheatherNumber(char c){
    return c > '0' && c < '9' ? 1:0;
    }

程序中的内联函数在程序编译时,将函数替换至程序中函数调用位置,造成程序变长,效率提高。
注意事项:
内联函数中不能出现循环、switch语句等
内联函数一般短小,不宜过长
应在调用之前声明或定义
函数模版
有些函数重载时参数个数相同,只是类型不同,此时重载函数比较繁琐,可利用函数模版实现。
例子:
ini复制代码template
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 类名::函数名(){
}


go复制代码```  


:: 称为域限定符,表示函数是类的成员函数。在类外使用域限定符定义函数,若想定义为内联,加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,析构函数不可以重载,析构函数在对象生命周期结束的时候由系统自动调用。


定义析构函数
例子:
arduino复制代码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类似)
例子:
ini复制代码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.普通函数作为一个类的友元
例子:
arduino复制代码  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类的友元
例子:
kotlin复制代码 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类的友元
arduino复制代码  class B{
  
   private:
      int y;
   public:
      B(int b){y = b;}
      int getY(){return y;}
      friend class A;
  }

const对象
const 可限定变量、指针、对象
函数、数据成员、成员函数。便是不可改变。
const对象只能调用const成员函数
例子:
arduino复制代码 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.改变基类的成员的访问权限。
单一继承

一般形式
arduino复制代码 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限定。


类模版与向量
类模版

类模版的基础知识
arduino复制代码template<class T> class 类名{
 .....
}



xml复制代码类模版的对象:类名<模版参数> 对象名(参数); 

kotlin复制代码模版类的成员函数定义形式: 
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(){}  //空


多重继承与虚函数
首先,多重继承是多个单一继承的集合。
类成员函数的指针与多态性
在派生类中,当一个指向基类成员函数的指针指向一个虚函数,并且通过指向对象的基类指针(或引用)访问这个虚函数时,会发生多态性。
运算符重载和流类库
运算符重载


重载对象的赋值运算符


运算符重载的实现


<< >> 和 ++ 运算符重载的实例
例子:
kotlin复制代码  //插入符函数的一般形式
 ostream &operator<<(ostream& output,类名& 对象名){
    return output;
 }



类运算符和友元运算符的区别


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


流类库


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

.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:16px;overflow-x:hidden;color:#252933}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:24px;line-height:38px;margin-bottom:5px}.markdown-body h2{font-size:22px;line-height:34px;padding-bottom:12px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:20px;line-height:28px}.markdown-body h4{font-size:18px;line-height:26px}.markdown-body h5{font-size:17px;line-height:24px}.markdown-body h6{font-size:16px;line-height:24px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}为什么要学习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注释类似)

arduino复制代码/*....*/  
//.... 


输入输出流
cin和cout是C++语言中进行输入输出操作的函数,定义在istream头文件中。
例子:

bash复制代码cout << "" << endl;  //c代表c系语言,out代表输出,endl代表换行 


使用命名空间
命名空间是C++语言中封装程序库名称的一种机制
C++ 标准类库中的对象和函数都属于std命名空间,使用这些函数和对象时要using namespace std
arduino复制代码#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++允许一个函数定义多个版本,使得一个函数完成多种功能,即同一个函数名定义多次。
例子:
css复制代码 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来观察这些数据类型的长度
例子:
c复制代码 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.&取地址符(取某一个变量的地址)
例子:
css复制代码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.不能直接定义数组的引用


arduino复制代码使用typedef定义某类型的别名   

arduino复制代码一般格式: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.指向常量的常量指针  

ini复制代码例子:

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.cc++.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是换行的意思
}
}; //注意结构数据定义完后要有分号

csharp复制代码void main(){

css复制代码 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关键字,则产生封装性。
例子:
csharp复制代码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。

使用构造函数初始化结构的对象
在定义结构时,与结构同名的函数称为构造函数。
如果定义的函数与某个已定义函数重名而参数类型或者个数不同,则称为函数重载。
例子:

ini复制代码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即变为类的标准定义形式。
例子:
ini复制代码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关键字表示该函数为内联函数。
例子:
arduino复制代码inline int wheatherNumber(char c){
 return c > '0' && c < '9' ? 1:0;
}

程序中的内联函数在程序编译时,将函数替换至程序中函数调用位置,造成程序变长,效率提高。
注意事项:
内联函数中不能出现循环、switch语句等
内联函数一般短小,不宜过长
应在调用之前声明或定义
函数模版
有些函数重载时参数个数相同,只是类型不同,此时重载函数比较繁琐,可利用函数模版实现。
例子:
ini复制代码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 类名::函数名(){
}

go复制代码```

:: 称为域限定符,表示函数是类的成员函数。在类外使用域限定符定义函数,若想定义为内联,加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,析构函数不可以重载,析构函数在对象生命周期结束的时候由系统自动调用。

定义析构函数
例子:
arduino复制代码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类似)
例子:
ini复制代码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.普通函数作为一个类的友元
例子:
arduino复制代码 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类的友元
例子:
kotlin复制代码 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类的友元
arduino复制代码 class B{

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

const对象
const 可限定变量、指针、对象
函数、数据成员、成员函数。便是不可改变。
const对象只能调用const成员函数
例子:
arduino复制代码 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.改变基类的成员的访问权限。
单一继承

一般形式
arduino复制代码 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限定。

类模版与向量
类模版

类模版的基础知识
arduino复制代码template class 类名{
.....
}

xml复制代码类模版的对象:类名<模版参数> 对象名(参数);

kotlin复制代码模版类的成员函数定义形式:
template 返回值类型 类名::函数名(参数){
//函数体
}

类模版的派生与继承
模版类继承普通类,模版类作普通类的派生类。
继承后成员使用与一般类的继承成员使用一样。
模版类派生模版类。
模版类使用时,须指出模版类参数。

向量与泛型算法

定义向量列表
向量是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(){} //空

多重继承与虚函数
首先,多重继承是多个单一继承的集合。
类成员函数的指针与多态性
在派生类中,当一个指向基类成员函数的指针指向一个虚函数,并且通过指向对象的基类指针(或引用)访问这个虚函数时,会发生多态性。
运算符重载和流类库
运算符重载

重载对象的赋值运算符

运算符重载的实现

<< >> 和 ++ 运算符重载的实例
例子:
kotlin复制代码 //插入符函数的一般形式
ostream &operator<<(ostream& output,类名& 对象名){
return output;
}

类运算符和友元运算符的区别

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

流类库

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

作者:清水河畔
链接:https://juejin.cn/post/6869005618854936583
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。