C++六个默认成员函数

一.默认构造

构造函数是特殊的成员函数,构造函数并不进行对成员变量开空间(局部变量在栈帧创建时,就已经有空间了),构造函数是为了初始化成员变量,构造函数是创建对象时会自动调用的

构造函数有以下特点:

  • 函数名与类名相同

  • 构造函数不需要返回值

  • 对象实例化时会自动调用构造函数

  • 构造函数可以重载

  • 如果没有显示的创建构造函数,编译器会默认生成一个无参默认构造函数,当用户显示定义时就不会存在

  • 无参构造函数,全缺省构造函数,以及编译器默认生成的构造函数都叫做构造函数,半缺省构造不能叫做默认构造函数;而且三者只能存在其一,不能同时存在无参构造和全缺省构造重载但会有调用歧义;

    //加入有个类A
    A a;
    A a(1,2);//假如是半缺省
    //类似这样只要没传参的调用才是 默认构造

  • 编译器默认生成的构造函数对内置类型成员变量不会进行初始化,其初始值取决于编译器实现。对于自定义类型成员变量,编译器会尝试调用该类型的默认构造函数进行初始化。若该类型没有默认构造函数,则会导致编译错误。

二.析构函数

析构函数与构造函数的功能相反,析构函数并不是完成对对象本身的摧毁,变量生命周期到了,自己就摧毁了,而是需要我们将变量所分配的空间给释放掉,C++在对象销毁时会自动调用析构函数,所有没有动态开辟空间的类是不需要析构函数的,调用编译器默认的即可

析构函数特点

  • 析构函数名是在类名前加上~

  • 无参数无返回值

  • 一个类只有一个析构,未显示定义编译器会生成

  • 对象生命周期结束会自动调用析构函数

  • 与构造函数相似,不显示写编译器析构函数对内置类型不做处理,自定义类型调用自定义类型的析构函数

  • 显示的写析构函数时,自定义类型的成员也会调用它的析构函数,注意不要给自定义成员析构两次

  • 当类中无需管理资源时,可以省略析构函数的显式定义,直接使用编译器生成的默认析构函数。

  • 一个局部域的对象,C++规定后定义的先析构

三.拷贝构造函数

如果构造函数第一个参数是自身类型的引用,且任何额外参数都有默认值,则此构造函数叫做拷贝构造函数

拷贝构造函数特点

  • 拷贝构造函数是构造函数的一个重载

  • 拷贝构造函数第一个参数必须是类类型的引用传参,传值引用会导致无限递归的问题。拷贝构造函数可以接受多个参数,但第一个参数必须是该类类型对象的引用,后续参数则必须提供默认值。

  • C++规定自定义类型的对象进行拷贝必须调用拷贝构造,所以自定义类型的传值传参和传值返回都会调用拷贝构造

  • 若未显示生成构造函数,编译器会生成一个,自动生成的拷贝构造对内置类型会完成值拷贝/浅拷贝,自定义类型会调用其自己的拷贝构造

  • 如果一个类内没有分配资源,编译器自动生成的拷贝构造即可,但如果一个类需要分配资源,使用自动生成的拷贝就会有问题,因为浅拷贝,会让两个变量指向同一块资源,这明显不是我们想要的,所以需要自己实现默认构造函数达成深拷贝

  • 传值返回会产生一个临时对象调用拷贝构造,所以当传值传参进行创建拷贝构造时,参数需要调用拷贝构造,这就导致了参数需要拷贝构造去创建,而拷贝构造的参数也需要拷贝构造,造成无限递归。但如果所返回的对象是局部内创建的,局部结束就销毁,传引用返回也就会有问题,类似野指针,所以要确保出了函数返回的引用对象还在

    class A;
    A a;
    A b=a;//调用的也是拷贝构造

四.运算符重载

在C++中,当运算符作用于类类型的对象时,可以通过运算符重载来赋予其新的含义。C++规定类类型对象使用运算符时,必须转换为调用对应的运算符重载函数,若未定义相应重载则会引发编译错误。

运算符重载函数的特性:

  • 由关键字operator和运算符符号共同构成函数名
  • 与其他函数类似,具有返回类型、参数列表和函数体
  • 参数数量与运算符作用的运算对象数量一致:
    • 一元运算符:1个参数
    • 二元运算符:2个参数(左侧对象传给第一个参数,右侧对象传给第二个参数)
  • 作为成员函数时,第一个运算对象默认绑定到this指针,因此参数数量比运算对象少一个
  • 重载后保持原运算符的优先级和结合性

运算符重载的限制:

  1. 不能创建语法中不存在的运算符(如operator@
  2. 以下5个运算符不可重载(需重点记忆):
    • .*
    • ::
    • sizeof
    • ?:
    • .
  3. 必须至少包含一个类类型参数,不能改变内置类型运算符的含义
  4. 应选择对类有实际意义的运算符进行重载(如Date类适合重载operator-而非operator+

特殊运算符重载注意事项:

  • 区分前置++和后置++:
    • 后置++需添加int形参以构成重载
  • 流运算符<<>>
    • 需重载为全局函数

    • ostream/istream作为第一个参数

    • 类类型对象作为第二个参数

    • 避免因this指针导致调用形式不符合常规习惯(如对象<<cout

      //区分
      class A;
      A a;
      A b=a;//调用拷贝构造函数
      A c;
      c=a;//调用赋值重载运算符

五.赋值运算符重载

赋值运算符重载是类的默认成员函数,用于实现两个已存在对象间的拷贝赋值操作。需要注意的是,它与拷贝构造函数有所区别:拷贝构造函数用于在创建新对象时通过已有对象进行初始化。

  • 赋值运算符重载是一个运算符重载,规定必须重载为成员函数
  • 有返回值,目的为了连续的赋值
  • 当未显式实现时,编译器会自动生成默认的赋值运算符重载函数。该默认函数的行为类似于默认拷贝构造函数:对于内置类型的成员变量执行逐字节的值拷贝(浅拷贝),对于自定义类型的成员变量则调用其自身的赋值运算符重载函数。

六.取地址运算符重载

const成员函数

复制代码
class A{
void print(){}
}
const A a;
a.print()//调用不了因为 默认print里面this参数是 A this类型而传入的是 const A this类型导致权限放大
如果把 void print()const{}
就可以使用a.print();了
  • 将const修饰的成员函数成为const成员函数,const放在函数参数列表后面
  • const 修饰该成员函数时,实际上是作用于隐含的 this 指针,表示在该成员函数中不能修改类的任何成员。对于 Date 类的 Print 成员函数,当使用 const 修饰后,其隐含的 this 指针类型会从 Date* const this 变为 const Date* const this

取地址运算符重载有两种一个是非const一个是const一般默认生成的就可以用了;

复制代码
Date* operator&()
{
return this;
} 
const Date* operator&()const
{
return this;
}

七.构造函数参数列表

  • 构造函数除了在函数体内赋值,还可以用参数列表进行赋值,初始化列表。
  • 每个成员变量在初始化列表只能出现一次,不能多次赋值,可以理解成初始化列表是每个成员初始化定义的地方
  • 引用成员变量和const成员变量只能在初始化列表初始化,因为在默认构造函数体内无法给他们赋值
  • C++11支持成员变量声明时缺省,这个缺省值是给没有初始化列表的成员变量用的
  • 即使没有显示的使用参数列表,成员变量也会走参数列表,因为相当于给变量一个定义
  • 初始化列表初始化顺序与列表顺序无关,而是与变量声明顺序一致

类型转换

C++ 支持将内置类型隐式转换为类类型对象,这需要类中定义了以该内置类型为参数的构造函数。

关键点:

  • 若在构造函数前添加 explicit 关键字,则会禁用该隐式转换功能
  • 类类型对象之间也可以进行隐式转换,前提是提供了相应的构造函数支持

static成员变量

使用static修饰的成员变量称为静态成员变量,必须在类外进行初始化。

特点:

  1. 静态成员变量由所有类对象共享,不属于特定对象,存储在静态区而非对象内存中
  2. 使用static修饰的成员函数称为静态成员函数,没有this指针
  3. 静态成员函数可以访问其他静态成员,但不能访问非静态成员(因缺少this指针)
  4. 非静态成员函数可以访问所有静态成员变量和函数
  5. 访问方式:
    • 通过类名::静态成员
    • 通过对象.静态成员
  6. 静态成员同样受public/protected/private访问权限限制
  7. 静态成员变量不能在声明处用缺省值初始化,因为:
    • 缺省值用于构造函数初始化列表
    • 静态成员不属于特定对象
    • 不通过构造函数初始化列表进行初始化
相关推荐
亭上秋和景清3 小时前
指针进阶:函数指针详解
开发语言·c++·算法
胡萝卜3.03 小时前
C++现代模板编程核心技术精解:从类型分类、引用折叠、完美转发的内在原理,到可变模板参数的基本语法、包扩展机制及emplace接口的底层实现
开发语言·c++·人工智能·机器学习·完美转发·引用折叠·可变模板参数
9ilk3 小时前
【C++】--- C++11
开发语言·c++·笔记·后端
FMRbpm4 小时前
队列练习--------最近的请求次数(LeetCode 933)
数据结构·c++·leetcode·新手入门
biter down4 小时前
C++ 函数重载:从概念到编译原理
开发语言·c++
ZouZou老师5 小时前
C++设计模式之解释器模式:以家具生产为例
c++·设计模式·解释器模式
无限进步_5 小时前
深入理解 C/C++ 内存管理:从内存布局到动态分配
c语言·c++·windows·git·算法·github·visual studio
JANGHIGH5 小时前
c++ 多线程(三)
开发语言·c++
点云SLAM6 小时前
C++ 中traits 类模板(type traits / customization traits)设计技术深度详解
c++·算法·c++模板·c++高级应用·traits 类模板·c++17、20·c++元信息