C++的学习
1、区别1
变量的定义
C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。
区别: C语言中的变量都必须在作用域开始的位置定义!!
2、区别2
register关键字的变化
register关键字请求“编译器”将局部变量存储于寄存器中
C语言中无法取得register变量地址
在C++中依然支持register关键字
C++编译器有自己的优化方式,不使用register也可能做优化
C++中可以取得register变量的地址
C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。,c++的编译器中做的优化比我们程序员要的多多的。如果,有人对register
变量取址,那么编译器就会视为普通变量,本来可能视为register变量了。
早期C语言编译器不会对代码进行优化,因此register变量是一个很好的补充。
3、区别三
在C语言中,重复定义多个同名的全局变量是合法的,严重影响可读性
在C++中,不允许定义多个同名的全局变量
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上。但C++直接拒绝这种二义性的做法。
4 区别四
C++语言的const的优化。
C语言中的const变量
C语言中const变量是只读变量,有自己的存储空间,可以通过指针对其进行修改,
C++中的const是常量,只有在取址的时候,或者发现Extern, 才去分配空间,const变量在符号表中作为常量存储,当再次访问时时,由于优化的原因会直接从符号表里面访问他的值,并不会因为指针改变了他的空间的值而使值改变
既然值不用,为什么需要这一语法,可以通过内存改变值呢?
为了兼容C语言,
int array[a + b] = {0}; //在C语言中,a,b作为变量,所以a+b在编译的时候是无法知道其大小的,只用在运行时才可以访问得到,而在c++中,const修饰的表示是常量,从符号表中读取,
Const和#define 的区别
Const 有严格的类型检查,和作用域的检查,而#define没有作用域的检查和类型的检查,它只是简单的文本替换。
C++中的const常量类似于宏定义
const int c = 5; ≈ #define c 5
C++中的const常量在与宏定义不同
const常量是由编译器处理的,提供类型检查和作用域检查
宏定义由预处理器处理,单纯的文本替换
区别五:
struct类型的加强:
C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
C++中的struct是一个新类型的定义声明
区别六:
C语言中默认为整形,且函数无参时表示可以接受任一个参数(注 但是不可以访问到仍和一个)
C++中所有的变量和函数都必须有类型
C语言中的默认类型在C++中是不合法的
在C语言中
int f();表示返回值为int,接受任意参数的函数
int f(void);表示返回值为int的无参函数
在C++中
int f();和int f(void)具有相同的意义,都表示返回值为int的无参函数
第一节课的总结
C++以C语言为基础进行了加强
C++更强调实用性,可以在任意的地方声明变量
C++中的register只是一个向后兼容的作用,C++编译器能够进行更好的变量优化
C++中的const是一个真正意义上的常量,而不是只读变量
C++更加强调类型,任意的程序元素都必须显示指明类型
C++中的布尔类型
C++在C语言的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
理论上bool只占用一个字节,
如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现
Tip:
true代表真值,编译器内部用1来表示
false代表非真值,编译器内部用0来表示
bool类型只有true(非0)和false(0)两个值
C++编译器会在赋值时将非0值转换为true,0值转换为false
C语言中的三目运算符返回的是变量值,不能作为左值使用
C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方
注意:
三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用
引用:
变量名回顾
变量是一段实际连续存储空间的别名
程序中通过变量来申请并命名存储空间
通过变量的名字可以使用存储空间
思考:
对于一段连续的存储空间只能有一个别名吗?
不仅仅只有一个别名,和java中的引用是异曲同工的吗?
在C++中新增加了引用的概念
引用可以看作一个已定义变量的别名
引用的语法:Type& name = var;
Tip:
普通引用在声明时必须用其它的变量进行初始化。
引用的意义
引用作为其它变量的别名而存在,因此在一些场合可以代替指针
引用相对于指针来说具有更好的可读性和实用性,指针如果不通过定义,可能会理解错,
例如: swap(&a,&b) 以为交换指针
但是引用 swap(a,b)交换a,b变量的值
Tip:
引用作为函数参数声明时不进行初始化。
Const引用 表示的是该变量是只读变量可以通过指针进行修改。
当使用常量对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
Tip:
使用常量对const引用初始化后将生成一个只读变量。
立即数是一个常量,要对其用常引用才可以使用。
Const Int &a = 3;
引用有自己的存储空间吗?
答,引用有自己的存储空间
引用在C++中的内部实现是一个常指针
Type& name çèType* const name
修饰的内容不可改变。
Improtance:
C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏。
当函数返回值为引用时
若返回栈变量
不能成为其它引用的初始值
不能作为左值使用
若返回静态变量或全局变量
可以成为其他引用的初始值
即可作为右值使用,也可作为左值使用
总结
1、bool类型是C++新增加的基础类型,其值只能是true和false
2、C++中的引用可以看作变量的别名来使用
3、C++中的常引用可以使得一个变量拥有只读属性
4、C++中的常引用可以用常量初始化而得到一个只读变量
5、C++中引用的本质是一个指针常量
在C++中不允许定义引用数组Type& a[N],为什么?
如何定义一个数组的引用?如何定义一个函数引用?
数组引用和数组指针有什么区别?函数引用和函数指针又有什么区别?
解答:
内联函数
1、C++中推荐使用内联函数替代宏代码片段
2、C++中使用inline关键字声明内联函数
3、内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。
C++编译器可以将一个函数进行内联编译
被C++编译器内联编译的函数叫做内联函数
内联函数在最终生成的代码中是没有定义的
C++编译器直接将函数体插入函数调用的地方
内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)
C++编译器不一定准许函数的内联请求!
内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型等)
内联函数是对编译器的一种请求,因此编译器可能拒绝这种请求
内联函数由编译器处理,直接将编译后的函数体插入调用的地方
宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程
C++中内联编译的限制:
不能存在任何形式的循环语句
不能存在过多的条件判断语句 不能有switch case
函数体不能过于庞大 最好不要超过五句
不能对函数进行取址操作 不能对函数取之操作,不然拒绝内联操作
函数内联声明必须在调用语句之前 不然拒绝内联操作
编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。
因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。
C++的默认参数值
C++中可以在函数声明时为参数提供一个默认值,当函数调用时没有指定这个参数的值,编译器会自动用默认值代替
函数默认参数的规则
只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值
在C++中可以为函数提供占位参数
占位参数只有参数类型声明,而没有参数名声明,但是参数的数目必须匹配
一般情况下,在函数体内部无法使用占位参数
例如:
int func(int a, int b, int = 0)
{
return a + b;
}
int main(int argc, char *argv[])
{
printf("func(1, 2, 3) = %d\n", func(1, 2,3));
printf("Press enter to continue ...");
getchar();
return 0;
}
占位参数的意义是什么?
意味着用户的需求可能改变,提供占位参数来提供参数,为后期维护的人员有线索来改善程序。
可以将占位参数与默认参数结合起来使用
意义
为以后程序的扩展留下线索
兼容C语言程序中可能出现的不规范写法
比如
Int fun()
{
Return ;
}
C语言中调用直接用fun(1),只需要用一个占位参数就可以实现兼容了。
小结
1、C++中可以通过inline声明内联函数
2、内联函数在编译时直接将函数体插入函数调用的地方
3、inline只是一种请求,编译器不一定允许这种请求
4、内联函数省去了普通函数调用时压栈,跳转和返回的开销
5、C++中在声明函数的时候指定参数的默认值
6、C++可以声明占位符参数,占位符参数一般用于程序扩展和对C代码的兼容
重载
重载(Overload)
同一个标识符在不同的上下文有不同的意义
如:
“洗”和不同的词汇搭配后有不同的含义
洗衣服,洗脸,洗脑,洗马桶, 。。。
“play”和不同的单词搭配后有不同的含义
play chess, play piano, play basketball …
函数重载至少满足下面的一个条件:
参数个数不同
参数类型不同
参数顺序不同
当函数默认参数遇上函数重载会发生什么?
会容易出错,重载和默认参数选择其中一个就行,否则容易出错
ambiguous call to overloaded function
编译器调用重载函数的准则
将所有同名函数作为候选者
尝试寻找可行的候选函数
精确匹配实参
通过默认参数能够匹配实参
通过默认类型转换匹配实参
匹配失败
最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。
无法匹配所有候选者,函数未定义,编译失败。
函数重载的注意事项
重载函数在本质上是相互独立的不同函数
重载函数的函数类型是不同的
函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的
函数重载与函数指针
当使用重载函数名对函数指针进行赋值时
1、根据重载规则挑选与函数指针参数列表一致的候选者
2、严格匹配候选者的函数类型与函数指针的函数类型
3、会对参数进行自动转换,如果在范围内,可以自行转换,如果不是,就是错误。
4、传参实际上是一个初始化,他可以自动转化,在其大小范围内例如:2,可以在char,short,int,long
在项目中融合C++和C代码是实际工程中不可避免的
虽然C++编译器能够兼容C语言的编译方式,但C++编译器会优先使用C++的方式进行编译
利用extern关键字强制让C++编译器对代码进行C方式编译
C++编译器不能以C的方式编译多个重载函数
函数重载是C++对C语言的一个重要升级
函数重载通过函数参数列表区分不同的同名函数
函数的返回值类型不是函数重载的依据
extern关键的关键能够实现C和C++的相互调用
深入理解重载规则
精确匹配实参
通过默认类型转换匹配实参
通过默认参数匹配实参
三条规则会同时对已存在的重载函数进行挑选
当实参为变量并能够精确匹配形参时,不再进行默认类型转换的尝试。
当实参为字面量时,编译器会同时进行精确匹配和默认类型转换的尝试。
C++中的动态内存分配
C++中通过new关键字进行动态内存申请
C++中的动态内存申请是基于类型进行的
delete关键字用于内存释放
注意一个C语言中的malloc 用 free();
而c++ 的new 最好用delete;
变量申请:
Type* pointer = new Type;
// ……
delete pointer;
数组申请
Type* pointer = new Type[N];
// ……
delete[] pointer;
// ……
new关键字与malloc函数的区别
New不主动初始化,只有用小括号才进行初始化的。
new关键字是C++的一部分,malloc是由C库提供的函数
new以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配
new在申请单个类型变量时可进行初始化,malloc不具备内存初始化的特性
在C语言中只有一个全局作用域
C语言中所有的全局标识符共享同一个作用域
标识符之间可能发生冲突
C++中提出了命名空间的概念
命名空间将全局作用域分成不同的部分
不同命名空间中的标识符可以同名而不会发生冲突
命名空间可以相互嵌套
全局作用域也叫默认命名空间
C++命名空间的使用:
使用整个命名空间:using namespace name;
使用命名空间中的变量:using name::variable;
使用默认命名空间中的变量:::variable
默认情况下可以直接使用默
注意如果局部变量屏蔽掉全局变量,就要使用
Usin指令,全局变量 ::globevarilable
认命名空间中的所有标识符。
new关键字的初始化
static_cast强制类型转换
1、用于基本类型间的转换,但不能用于基本类型指针间的转换
2、用于有继承关系类对象之间的转换和类指针之间的转换
const_cast强制类型转换
用于去除变量的const属性
Example:
#include <stdio.h>
int main(int argc, char *argv[])
{
const int &j = 1;
int &k = const_cast<int &>(j); //注意强制转换都是把这个的副本转化成这个类//型,原本的还不能改变,j的const的属性改变了
printf("%d\n",k);
const int x = 3;
int &f = const_cast<int &>(x);
printf("%d\n",f);
//printf("Hello, world\n");
//getchar();
return 0;
}
reinterpret_cast强制类型转换
用于指针类型间的强制转换
用于整数和指针类型间的强制转换
reinterpret_cast直接从二进制位进行复制,是一种极其不安全的转换。
dynamic_cast强制类型转换
主要用于类层次间的转换,还可以用于类之间的交叉转换
dynamic_cast具有类型检查的功能,比static_cast更安全
C++中内置了动态内存分配的专用关键字 new delete
C++中的动态内存分配是基于类型进行的
C++中命名空间概念用于解决名称冲突问题
C++细化了C语言中强制类型转换的方式
C++不推荐在程序中使用强制类型转换
C++建议在强制类型转换时考虑一下究竟希望什么样的转换
深入理解extern “C”
extern “C”告诉编C++译器将其中的代码进行C方式的编译
C方式的编译主要指按照C语言的规则对函数名进行编译
函数名经过编译后可能与源码中的名字有所不同
C++编译器为了支持重载,函数名经过编译后会加上参数信息,因而编译后的函数名与源码中完全不同
C编译器不会在编译后的函数名中加上参数信息
extern “C”中的重载函数经过C方式编译后将得到相同的函数名,因此extern “C”中不允许重载函数,但extern “C”中的函数可以与extern “C”之外的函数进行重载。
深入理解extern “C”
extern “C”告诉编C++译器将其中的代码进行C方式的编译
C方式的编译主要指按照C语言的规则对函数名进行编译
函数名经过编译后可能与源码中的名字有所不同
C++编译器为了支持重载,函数名经过编译后会加上参数信息,因而编译后的函数名与源码中完全不同
C编译器不会在编译后的函数名中加上参数信息
面向对象学习
基本概念
类和对象是面向对象中的两个基本概念
“类”指的是一类事物,是一个抽象的概念
“对象”指的是属于某个类的一个实体,是一个具体存在的事物
类是一种“模板”,可以通过这种模板创建出不同的对象“实例”
对象“实例”是类“模板”的一个具体实现
一个类可以有很多对象,而一个对象必然属于某个类
类和对象的意义
类用于抽象的描述一类事物所特有的属性和行为
如:电脑类的每个对象都有CPU,内存和硬盘,电脑类的每个对象都可以开机和运行程序
对象是一个具体的事物,拥有其所属类的所有属性,并且每个属性都是一个特有的值
如:老虎的每个对象(也就是每只老虎),都有不同的体重,不同食量以及不同的性情
类之间的关系
根据生活中的经验,我们可以把事物进行分类,类之间的界限一般都是很清晰的,如电脑类和老虎类
但是一些类可以再细分,如电脑类可以再分为Dell类,Sony类以及HP类等等
从同一个类细分出来的类和原来的类之间是有关系的,这种关系叫做继承,如HP类继承了电脑类
继承的类拥有原类的所有属性,如HP电脑就是一种电脑,HP电脑也同样的拥有CPU,内存和硬盘
深入理解类
不但可以抽象的描述一类事物的属性,也可以抽象的描述一类事物的行为
从同一个类细分出来的类不但继承了原有类的属性同时也继承了原有类的行为
继承出的新类可以拥有自己特有的属性和行为
属性主要用于描述类的静态特性,行为主要用于描述类的动态特性
如:老虎类的属性有颜色,体重,而行为有捕猎和逃跑,而兔子类的属性也有颜色和体重,但是兔子类的行为没有捕猎,只有逃跑
另外,从一个更高的层面看,老虎和兔子都属于动物类,它们都继承了动物类的属性和行为,另外又又自己特定的属性和行为
深入理解对象
对象是一个类的实例,所谓实例即一个类中的特定的事物
一个类可以有多个实例,并且这些实例之间是互不相同的
如:人这个类中有几十亿个不同的个体,每一个人都是人这个类的一个实例
对象和类的关系如同模具和成品的关系,类就是一个模具,利用这个模具可以生成多个不同的成品,而这些成品就是各不相同的对象
同一个类的不同对象都有对应的类中的属性和行为,但是这些属性和行为可能不完全相同
类的表示法—最终方案
改进3的方法开始引入C语言的语法,将表示法推广给编译器
考虑一下:是不是可以再改进一下让编译器完全读懂呢?
再找共同点:每个类中只有属性和行为,属性是静态特性,行为是动态特性
C++编译器支持变量和函数,根据相似性考虑用变量表示属性,用函数表示行为
类和对象是面向对象方法论中的两个基本概念
类指的是生活中有共同特性的一类事物
对象是类的一个具体实例,拥有所属类的特征
一个类可以有多个对象
一个对象必然属于某个类
面向对象方法论直接将生活中的事物映射到程序中
寻找生活中类的列子
利用本课中的方法用C++描述类和类之间的关系
生成类的实例并调用使用类的属性和行为
类的访问权限
C++中类的封装
成员变量
C++中用于表示类属性的变量
成员函数
C++中用于表示类行为的函数
在C++中可以给成员变量和成员函数定义访问级别
public
成员变量和成员函数可以在类的内部和外界访问和调用
private
成员变量和成员函数只能在类的内部被访问和调用
类成员的作用域都只在类的内部,外部无法直接访问
成员函数可以直接访问成员变量和调用其它成员函数
类的外部可以通过类变量访问public成员
类成员的作用域与访问级别没有关系
外部必须通过类名和对象名才可以访问。
Struct和class的用法完全一致,权限上struct 的默认权限为public,而class的默认权限是private.
运算类的改进
在Operator中所有成员函数的实现都在类中完成
问题:对于使main函数来说,只需要知道怎么使用Operator即可,没有必要知道其实现
解决方案:将Operator类的实现和定义分开
Operator.h头文件中只有类的声明
Operator.cpp中完成类的其它实现
类的精华在于封装
将实现细节和使用方式相分离
C++中通过public和private实现类的封装
public成员可以通过变量被外界访问
private成员只能够在类内部使用
类的定义和实现可以分开到不同的文件中
生活中存在的对象都是被初始化后才上市的
初始状态是对象普遍存在的一个状态的
一般而言所有的对象都需要一个确定的初始状态
解决方案
为每个类都提供一个public的initialize函数
对象创建后立即调用initialize函数进行初始化
initialize只是一个普通的函数,必须显示的调用
一旦由于失误的原因,对象没有初始化,那么结果将是不确定的
没有初始化的对象,其内部成员变量的值是不定的
C++中的类可以定义与类名相同的特殊成员函数
这种与类名相同的成员函数叫做构造函数
构造函数在定义时可以有参数,但是没有任何返回类型的声明
C++中的类可以定义与类名相同的特殊成员函数
这种与类名相同的成员函数叫做构造函数
构造函数在定义时可以有参数,但是没有任何返回类型的声明
构造函数的调用
一般情况下C++编译器会自动调用构造函数
在一些情况下则需要手工调用构造函数
两个特殊的构造函数
无参构造函数
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空
拷贝构造函数
当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,简单的进行成员变量的值复制 ,所有的成员变量都进行赋值。
默认的是所有的值复制,如果自定义的话,未做赋值操作时,默认为零。
一般而言所有被销毁的对象都需要做清理
解决方案
为每个类都提供一个public的destroy函数
对象不再被需要时立即调用destroy函数进行清理
C++中的类可以定义一个特殊的成员函数清理对象
这个特殊的成员函数叫做析构函数
定义:~ClassName()
析构函数没有参数也没有任何返回类型的声明
析构函数在对象销毁时自动被调用
无参,无重载,还必须自己去改写,不会默认分配一个析构函数,
构造函数与析构函数的调用秩序
当类中有成员变量是其它类的对象时
首先调用成员变量的构造函数
调用顺序与声明顺序相同
之后调用自身类的构造函数
析构函数的调用秩序与对应的构造函数调用秩序相反
可以直接调用构造函数,创建临时对象,调用完之后,立即析构了。
例如:
Test();
要点,避免在构造函数里调用构造函数。
注一个对象只能调用一次构造函数,否则是无效的。
析构函数是C++中对象销毁时做清理工作的特殊函数
析构函数在对象销毁时自动被调用
析构函数是对象所使用的资源及时释放的保障
析构函数的调用秩序与构造函数相反
可以直接调用构造函数,直接调用构造函数将得到一个临时对象。
通过对象名能够访问public成员变量
每个对象都可以有只属于自己的成员变量
成员变量不能在对象之间共享
统计类在程序运行期间有多少个对象同时存在
保证程序的安全性,并随时可以获取对象的数目
在C++中可以定义静态成员变量和静态成员函数
静态成员属于整个类所有,不需要依赖任何对象
可以通过类名直接访问public静态成员
可以通过对象名访问public静态成员
静态成员函数可以直接访问静态成员变量
从命名空间的角度
类的静态成员只是类这个命名空间中的全局变量和全局函数
不同之处只是,类可以对静态成员进行访问权限的限制,而命名空间不行
从面向对象的角度
类的静态成员属于类概念本身
类的所有对象共享相同的静态成员
C++标准库并不是C++语言的一部分
C++标准库是由C++语言编写而成的类库和函数的集合
C++标准库中定义的类和对象都位于std命名空间中
C++标准库的头文件都不带.h后缀
C++标准库涵盖了C库的功能
C库中<name.h>头文件对应C++中的<cname>
C++标准库预定义了多数常用的数据结构,如:字符串,链表,队列,栈等
add函数可以解决Complex变量相加的问题,但是Complex是现实世界中确实存在的复数,并且复数在数学中的地位和普通的实数相同
C++中操作符重载的本质
C++中通过operator关键字可以利用函数扩展操作符
operator的本质是通过函数重载实现操作符重载
用operator关键字扩展的操作符可以用于类吗???
操作符重载是C++的强大特性之一
操作符重载的本质是通过函数扩展操作符的语义
operator关键字是操作符重载的关键
friend关键字可以对函数或类开发访问权限
操作符重载遵循函数重载的规则
operator+的成员函数实现 :
用成员函数重载的操作符
比全局操作符重载函数少一个参数,即左操作数
不需要使用friend关键字
当无法修改左操作数的类时,使用全局函数进行重载
=, [], ()和->操作符只能通过成员函数进行重载
例如: (ostream &out,Test c1)
Ostream 是系统定义的类
所以必须定义为全局转载。
理解的方向
例如:cout<<c1; 全局函数调用的方式是 funtionnae(cout, c1)
局部函数: cout << c1的调用方式是 cout. . <<(funtionc1)
C++中的定义的
= ,[],(), -> 操作符只能通过成员函数进行重载。
C++编译器会为每个类提供默认的赋值操作符
默认的赋值操作符只是做简单的值复制
类中存在指针成员变量时就需要重载赋值操作符
操作符重载是通过函数重载实现的
C++中通过一个占位参数来区分前置运算和后置运算
前置运算的效率更高
面试题: 不要重载&&和||操作符
面试题,从语法上角度是可以重载的,但是使用上最好不要重载原因
&&和||是C++中非常特殊的操作符
&&和||内置实现了短路规则
操作符重载是靠函数重载来完成的
操作数作为函数参数传递
C++的函数参数都会被求值,无法实现短路规则
操作符重载可以直接使用类的成员函数实现
=, [], ()和->操作符只能通过成员函数进行重载
++操作符通过一个int参数进行前置与后置的重载
C++中不要重载&&和||操作符
malloc和free是库函数,以字节为单位申请堆内存
new和delete是关键字,以类型为单位申请堆内存
malloc和free单纯的对内存进行申请与释放
对于基本类型new关键字会对内存进行初始化
对于类类型new和delete还负责构造函数和析构函数的调用
面向对象中的继承指类之间的父子关系
子类拥有父类的所有成员变量和成员函数
子类就是一种特殊的父类
子类对象可以当作父类对象使用
子类可以拥有父类没有的方法和属性
注意:
C++中class的继承默认为private继承
private继承的子类拥有父类的所有成员
private继承使得父类的所有成员在子类中变为private成员
C++中的访问级别与继承
public继承
父类成员在子类中保持原有访问级别
private继承
父类成员在子类中变为private成员
Protected
父类成员在子类的继承,只是把成员public属性变成了protected
继承 = Max(要求更严的)(继承方式,访问方式)
继承是一种类之间的关系,子类是一种特殊的父类
子类通过继承可以得到父类的所有成员
private成员可以被子类继承但不能被子类访问
protected成员只能在当前类和子类中被访问
不同的继承方式可能改变继承成员的访问属性
子类对象可以当作父类对象使用
子类对象在创建时需要调用父类构造函数进行初始化
子类对象在销毁时需要调用父类析构函数进行清理
先执行父类构造函数,再执行成员构造函数
在继承中的析构顺序与构造顺序对称相反
同名成员通过作用域分辨符进行区分
继承是一种类之间的关系,子类是一种特殊的父类
子类通过继承可以得到父类的所有成员
private成员可以被子类继承但不能被子类访问
protected成员只能在当前类和子类中被访问
不同的继承方式可能改变继承成员的访问属性
子类对象可以当作父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
在子类对象构造的时候需要调用父类构造函数对其继承得来的成员进行初始化
注(课程按国嵌c++总结的)