为什么要学习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)提供的一组操作。利用这些操作可以简化数组操作。 要使用这些操作必须包含头文件\
假定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采用 .hpp|windows平台 .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 <iostream> //引入头文件 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 \; 注意:头文件引入的两种写法,#include <…> 和 #include “…” 。
类的初始化:string str1 = “A”;
string str1(“hello “); string str2 = “world”;
与java类似,string对象允许使用 + 运算- 使用complex对象
complex类用于定义一个复数对象,使用时添加头文件 #include \
定义格式:complex \num1(1,2); - 使用对象总结
使用标准类库中的类时,必须添加头文件。
定义对象方式同变量定义方式类似。
定义对象时可对对象进行初始化。
同类的不同对象由对象属性来区分。
不同类的对象具有不同的成员函数可实现不同操作。
类是具有相同特征和操作的对象的抽象。
- 使用complex对象
函数和函数模版
函数的参数及其传递方式
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 | 不可访问 | 不可访问 | 不可访问 |
public | public | 可访问 | 可访问 |
protected | protected | 不可访问 | 不可访问 |
- 私有派生
定义派生时,用private限定 。基类的公有成员和保护成员变为私有成员。 - 保护派生
定义派生时,用proetcted限定 。 降级使用,基类中的private变为不可访问,protect变为private,public变为protected。
多重继承
一般形式(java只能单一继承,c++可以多重继承):
class 类1:访问控制 lei2,访问控制 类3{
private:
//私有成员
protected:
//保护成员
public:
//公有成员
}
二义性及其支配原则
作用域和成员名限定
当派生类中从多个基类中继承得到同名函数时,在派生类中使用这些函数时,须使用类名限定!派生类的对象使用这些函数时,也需要进行类名限定!派生类支配基类的同名函数
在基类和派生类有重名的成员时,优先派生类的成员,如果要访问基类成员,必须加上左右域符号 ::
私有成员派生类不可访问,只有本类和友类可以访问
如果派生类要访问基类的成员,基类成员应该用protected限定。
类模版与向量
类模版
- 类模版的基础知识
类模版的对象:类名<模版参数> 对象名(参数); 模版类的成员函数定义形式: templatetemplate<class T> class 类名{
.....
}
返回值类型 类名 ::函数名(参数){ //函数体 } - 类模版的派生与继承
模版类继承普通类,模版类作普通类的派生类。
继承后成员使用与一般类的继承成员使用一样。
模版类派生模版类。
模版类使用时,须指出模版类参数。
向量与泛型算法
定义向量列表
向量是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(){} //空
多重继承与虚函数
首先,多重继承是多个单一继承的集合。
类成员函数的指针与多态性
在派生类中,当一个指向基类成员函数的指针指向一个虚函数,并且通过指向对象的基类指针(或引用)访问这个虚函数时,会发生多态性。