将抽象出的数据与代码封装在一起,形成类。需要使用外部接口来访问内部成员。
class 类名称
{
public:
公有成员 //外部接口 外部函数可以访问
private:
私有成员 //只能通过本类的函数访问
protected:
保护型成员
}
构造函数
为对象进行初始化的函数
构造函数的形式:- 函数名与类名相同
- 没有返回值
- 可以有形参,也可以没有
- 可以重载
- 可以有默认参数值
在对象创建时自动调用
默认构造函数调用时可以不需要实参的构造函数
- 参数表为空
Clock();
- 全部参数都有默认值
Clock(int newH = 0, int newM = 0, int newS = 0)
隐含生成的构造函数
如果类中未定义构造函数,编译器将在需要时自动生成默认构造函数
该函数
- 参数列表为空,不为数据成员设置初始值
- 如果类内定义了成员的初始值,则使用定义的初始值
- 如果类内没有定义初始值,则以默认方式初始化
- 基本类型数据默认初始化的值不确定
如果类内已经定义构造函数,编译器将不在隐含生成默认构造函数,若依然希望生成默认构造函数,可使用"= default"
class Clock{
public:
Clock() = default; //编译器隐含生成默认构造函数
Clock(int newH, int newM, int newS); //自定义构造函数
};
委托构造函数
对于多个参数表不同但算法相同的函数,为了书写简便,使用委托构造函数(特殊化到一般化)
/*不使用委托构造函数*/
Clock::Clock(int newH, int newM, int newS):hour(newH), minute(newM), second(newS){} //构造函数
Clock::Clock():
hour(0), minute(0), second(0){} //默认构造函数
/*使用委托构造函数*/
Clock::Clock(int newH, int newM, int newS):hour(newH), minute(newM), second(newS){}
Clock::Clock():Clock(0, 0, 0){}
复制构造函数
- 用已经存在的对象初始化一个新的对象,需要使用复制构造函数
- 隐含生成的复制构造函数可以实现数据成员的原封不动的复制
- 自定义的复制构造函数可以实现特殊的复制功能
- 是一种特殊的构造函数,形参为本类对象的引用
class 类名{
public:
类名(形参); //构造函数
类名(const 类名 &对象名) //复制构造函数
};
类名::类名(const 类名 &对象名){
函数体
} //复制构造函数的实现
当不希望对象被复制构造(不希望有重复的对象)时,使用"= delete"可以指示编译器不隐含生成默认复制构造函数
类名(const 类名 &对象名) = delete; //指示编译器不生成默认复制构造函数
复制构造函数被调用的三个情况:
- 使用一个已存在的对象作为初始值,定义一个新对象
- 一个函数的形参为类的对象,调用函数时,使用实参对象初始化形参对象
- 一个函数的返回值是类的对象,返回主调函数时,将使用return语句中的对象初始化一个无名对象,返回给主调函数
左值与右值:
- 左值:
位于赋值运算左侧的对象与变量,占用内存空间,有地址 - 右值:
位于赋值运算右侧的值,短暂存在,没有地址
左值引用与右值引用:
左值引用,用&
右值引用,用&&
float n = 6;
float &lr_n = n; //左值引用
float &&rr_n = n; //错误 n有地址 是左值
float &&rr_n = n * n; //n * n是短暂存在的一个值 是右值
float &&rr_n = move(n); //通过move函数将n这个左值对象移动到右值
移动构造函数:
参数为该类对象的右值引用,以移动数据方式构造新对象,作用与复制构造函数类似
类名(类名&& 对象名) noexpected:数据成员(move(对象名.数据成员)){}; //显式移动所有成员
析构函数
- 完成对象被删除前的清理工作
- 对象生存期结束时自动调用,释放对象所属空间
- 若未声明析构函数,编译器将自动生成
class 类名{
public:
~ 类名(); //析构函数
};
类的组合
- 类中的成员是另一种类的对象
- 在已有抽象的基础上实现更复杂的抽象
原则:
除了对本类中的基本类型成员初始化,也要对对象成员初始化
类A的成员函数f的形参是类B的对象,类B的成员函数g也以类A的对象为形参。无论将哪一个类的定义放在前面,都会引起编译错误。
前向引用声明,是在引用未定义的类之前,将该类的名字告诉编译器,使编译器知道那是一个类名。这样当程序中使用这个类名时,编译器就不会认为是错误的,而类的完整定义可以在程序的其他地方。
注意事项:
- 前向引用声明并不是万能的
- 提供完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象
- 使用前向引用声明时,只能使用被声明的符号,不能涉及类的任何细节
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)