C++学习笔记(三):类与对象

C++学习笔记(三):类与对象,第1张

C++学习笔记(三):类与对象 类的封装

将抽象出的数据与代码封装在一起,形成类。需要使用外部接口来访问内部成员。

class 类名称
{
    public:
        公有成员    //外部接口 外部函数可以访问
    private:
        私有成员    //只能通过本类的函数访问
    protected:
        保护型成员
}
构造函数

为对象进行初始化的函数

构造函数的形式:
  • 函数名与类名相同
  • 没有返回值
  • 可以有形参,也可以没有
  • 可以重载
  • 可以有默认参数值
构造函数的调用时机

在对象创建时自动调用

默认构造函数

调用时可以不需要实参的构造函数

  1. 参数表为空
   Clock();
  1. 全部参数都有默认值
   Clock(int newH = 0, int newM = 0, int newS = 0)
隐含生成的构造函数

如果类中未定义构造函数,编译器将在需要时自动生成默认构造函数
该函数

  • 参数列表为空,不为数据成员设置初始值
  • 如果类内定义了成员的初始值,则使用定义的初始值
  • 如果类内没有定义初始值,则以默认方式初始化
  • 基本类型数据默认初始化的值不确定
“= default”

如果类内已经定义构造函数,编译器将不在隐含生成默认构造函数,若依然希望生成默认构造函数,可使用"= 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;      //指示编译器不生成默认复制构造函数

复制构造函数被调用的三个情况:

  1. 使用一个已存在的对象作为初始值,定义一个新对象
  2. 一个函数的形参为类的对象,调用函数时,使用实参对象初始化形参对象
  3. 一个函数的返回值是类的对象,返回主调函数时,将使用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:
        ~ 类名();       //析构函数
};
类的组合
  1. 类中的成员是另一种类的对象
  2. 在已有抽象的基础上实现更复杂的抽象
类组合的构造函数设计

原则:
除了对本类中的基本类型成员初始化,也要对对象成员初始化

前向引用声明

类A的成员函数f的形参是类B的对象,类B的成员函数g也以类A的对象为形参。无论将哪一个类的定义放在前面,都会引起编译错误。
前向引用声明,是在引用未定义的类之前,将该类的名字告诉编译器,使编译器知道那是一个类名。这样当程序中使用这个类名时,编译器就不会认为是错误的,而类的完整定义可以在程序的其他地方。

注意事项:

  • 前向引用声明并不是万能的
  • 提供完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象
  • 使用前向引用声明时,只能使用被声明的符号,不能涉及类的任何细节

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/3002491.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存