静态成员
静态数据成员
初始化:只能在类外进行初始化
ex:
在A中有静态成员count,在类外进行初始化的格式为
1 | int A::count=0; |
静态成员函数
静态成员函数可以直接访问该类的静态数据成员和静态函数成员,访问非静态成员必须通过对象名。
析构函数
析构函数不能被重载
析构函数可以被继承
友元函数
1、友元关系是不能传递的
2、友元关系是单向的
3、友元关系是不能被继承的
常对象
常对象必须被初始化,而且不能够被更新
const是函数的一个组成部分,在函数的定义部分也要带有关键字const
常对象只能调用常函数
非常对象既可以调用常函数也可以调用非常函数,优先匹配非常函数
常量可以对非常量赋值,但是非常量不能对常量赋值
常数据成员
构造函数对常数据成员进行初始化就只能通过初始化列表
但是可以用静态常数据成员在类外进行初始化
ex
有声明:static const int b;
1 | const int A::b=10; |
访问控制
声明为private的函数,只能在本类的内部进行调用
异常处理
是在程序运行过程中遇到的不正常的情况,不是在程序设计过程中
能够解决的问题
1、环境条件出现意外
2、内存空间不足
3、人员操作错误
需要注意的是“编译错误”不属于异常处理的范畴
catch子句中声明的的异常类型就是抛出异常对象的“类型”或“引用”
在try块中构造的对象在异常准备抛出前会自动的调用对象的析构函数,执行顺序与构造顺序相反
如果说异常在某类对象还没有构造完成时,那么由于这个对象还没有构造完,将不会调用这个对象的析构函数
多态性
多态的实现方式
一、编译时多态
1.函数重载
2.运算符重载
二、运行时多态
1.继承+虚函数
消除二义性的方法
定义:在多继承中,父类有多个同名成员,或是有共同的基类,这时在派生类中访问这些成员可能会出现二义性。
1.函数重载
2.多继承
3.虚基类
哪些函数不能被声明为虚函数
- 内联函数
- 构造函数
- 非成员函数
- 静态函数
虚函数
1.虚函数的声明只能出现在函数的声明中,不能出现在函数的实现过程中
2.虚函数的调用要通过(函数成员)(指针)(引用)来访问虚函数
虚析构函数
通过基类的指针删除派生类的对象如果不将基类的析构函数声明为虚函数,那么调用的是基类的析构函数,派生类的析构函数不会被执行,派生类的空间不会被释放,就造成了内存泄漏
所以要用基类的指针删除派生类,就应该把基类的析构函数声明为虚函数
纯虚函数和抽象类
声明为纯虚函数后就可以不再给出函数的实现部分。
当析构函数声明为虚函数时,必须要给出实现。
基类中的纯虚函数在派生类中必须要给出实现。
ex
1 | virtual 函数类型 函数名(参数表)=0 |
带有纯虚函数的类叫做抽象类
抽象类里面有一些接口,但没有定义,只能在自己的派生类里面去定义
因而抽象类不能被实例化
如果说派生类中没有给出全部的纯虚函数的定义,那么这个派生类仍然为抽象类仍然不能够实例化
重载
条件:
1.在相同的作用域
2.有相同的函数名
3.形参的个数和类型不同
有一种情况是对于两个完全相同的函数,如果后一个函数被const修饰,那么他们也能构成重载。
运算符的重载
运算符重载至少有一个要是“自定义类型”
运算符重载为非成员函数的时候不一定是要重载为友元函数。
必须重载为全局函数的运算符
<< >>
必须重载为成员函数的运算符
= [] () ->
‘=’运算符重载最后返回的应该是 *this。
类和对象
对象所占据的内存空间只包括数据成员,函数成员不在对象里面存在副本,对于一个指针成员,存放的也仅仅是它的大小,不包括给他分配的内存空间。
更加权威的解释是
1.非静态成员变量的总和
2.加上编译器为了计算方便所作出的对齐处理
3.为了支持虚函数而产生的额外负担
相关链接
派生类和基类
派生类包含基类中所有的数据成员
基类中的私有数据成员在内存空间上是被继承了的,但是在派生类中是不可见的并且是无法访问的
构造函数和复制构造函数
1.既不写复制构造函数也不写构造函数系统将会自动的提供这两个默认函数
2.如果说只写了一个复制构造函数,那么系统将不会提供默认构造函数
3.如果说写了默认构造函数而没有写复制构造函数,系统会自动的提供复制构造函数。
调用复制构造函数的情况
1.用一个对象去初始化另外的一个对象的时候
2.当类的对象作为函数的形参,当函数的形参和实参结合的时候
3.当类的对象作为函数的返回值的时候。
需要注意的是,当我们用等号运算符‘=’去‘赋值’一个对象的时候,调用的是‘=’而不是赋值构造函数
在创建的时候用=,调用的是复制构造函数
派生类中构造函数和析构函数的调用顺序
1.调用基类的构造函数,对基类的数据成员进行初始化
2.调用内嵌对象的构造函数,对内嵌对象进行初始化
3.执行派生类的构造函数,对派生类的数据成员进行初始化
4.析构函数和构造顺序完全相反
数组指针和指针数组
这了我都搞忘了
int* p[10]指针数组,里面存放着的是int*
int(*p)[10]数0组指针,p现在是一个指针,它指向的是包含10个int类型的数组。
左值右值引用
定义引用的时候必须要给出初值
万能引用
1 | const int(类型)& a=? |
对于一个用户自定义的函数,如果函数参数为int &p,那么我们将不能把一个等式的运算值传给这个函数的参数。
ex;
函数
1 | void fun(int &d) |
函数调用
1 | fun(2)//wrong |
模板
再没提供模板实参的情况下,如果所给出的函数实参不一样,将会导致发生冲突,这时必须显式的给出模板实参。
例如
1 | template<class T> |
调用fun(4,4.5);一个int,一个double类型,将会导致无法确定T定成哪个类型
类模板的调用必须要有模板实参,即使是说有默认值的情况下也要写个 <>
类模板的实参列表指的是不包括’<>’里面的东西
动态内存分配
new 最后分配的结果是一个地址,如果创建的是一个类,A&a =*new B,在这里需要解引用。
new 和 delete是操作符,不是一个函数。
new int(n)的意思是分配一个int大小的内存空间并且赋初值n
new int[n]的意思是创建n大小的int数组
inline
在编译时不发生控制转移,在编译时将函数插到向相应的位置、
当内联函数被调用时,内联函数在被调用出展开。
c++关键字
final不是关键字!!!!!是说明符
using class const
本文作者: jiangyuhao
本文链接: http://example.com/2022/04/26/c-%E6%9C%9F%E6%9C%AB%E5%A4%8D%E4%B9%A0/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!