C++类的六个默认成员函数

本文详细介绍了C++中的构造函数、拷贝构造函数、析构函数、赋值运算符重载及取地址运算符重载的概念、特性和使用场景,并通过具体示例展示了它们的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述

  • 先来定义一个类
class A
{
};
  • 经过编译器处理之后,类A不在为空,它会自动的生成六个默认的成员函数,即使这六个成员函数什么也不做。(这些成员函数当我们没有定义时,编译器会显示的调用)处理之后相当于:
class A
{
public:
    A();//构造函数
    A(const A& a);//拷贝构造函数
    ~A();//析构函数
    A& operator=(const A& a);//赋值运算符重载
    A* operator &();//取地址运算符重载
    const A* operator &() const;//const修饰的取地址运算符重载
};
一、构造函数
1.概念
  • 构造函数:一个特殊的成员函数,名字与类名相同,创建类类型对象的时候,由编译器自动调用,在对象的生命周期内只且调用一次,以保证每个数据成员都有一个合适的初始值。
2.构造函数的特性
  • 函数名和类名相同;
  • 没有返回值;
  • 有初始化列表(可以不用);
  • 新对象被创建,由编译器自动调用,且在对象的生命周期内仅调用一次;
  • 构造函数可以重载,实参决定了调用哪个构造函数;
  • 如果没有显示的调用时,编译器会提供一个默认的构造函数;
  • 无参构造函数和带有缺省值的构造函数都认为是缺省构造函数,并且缺省构造函数只能有一个;
  • 构造函数不能用const修饰(因为const修饰类的成员函数时,该函数不能修改成员变量,但是构造函数要修改类的成员变量,因此不可以由const修饰
3.初始化列表
  • 以冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在圆括号中的初始化式。
    这里写图片描述
4.初始化顺序
  • 数据成员在类中定义的顺序就是参数列表中的初始化顺序;
  • 初始化列表仅用于初始化数据成员,并不指定这些数据成员的初始化顺序;
  • 每个成员在初始化列表中只能出现一次;
  • 尽量避免使用成员初始化成员,成员初始化顺序最好和成员的定义顺序保持一致。

类中包含以下成员必须要放在初始化列表中初始化:
(1)引用数据类型
(2)const数据类型
(3)类类型成员(该类没有缺省的构造函数)

5.默认构造函数
  • 默认构造函数使用与成员变量初始化相同的规则初始化成员,对于内置类型和复合类型的成员,如组、指针,只对定义在全局定义作用于的对象初始化,对于局部作用域的内置和复合类型不作初始化。
6.构造函数的作用
  • 构建对象
  • 初始化对象
  • 类型转换
7.explcit
  • 用explicit修饰构造函数,抑制由构造函数定义的隐式转换,explicit关键字类内部的构建声明上,在类的定义体外部的定义上不再重复。
二、拷贝构造函数
1.概念
  • 只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数称为拷贝构造函数。拷贝构造函数是特殊的构造函数,创建对象时使用已存在的同类对象来进行初始化,由编译器自动调用。
class CDate
{p
ublic:
CDate()
{}
CDate( const int year, const int month, const int day)
{
_iYear = year;
_iMonth = month;
_iDay = day;
} C
Date( const CDate& date){
_iYear = date._iYear;
_iMonth = date._iMonth;
_iDay = date._iDay;
}
private:
int _iYear;
int _iMonth;
int _iDay;
};
2.特征:

(1)它是构造函数的重载;
(2)它的参数必须使用同类型对象的引用传递;
(3)如果没有显示定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据成员完成初始化。

3.使用场景
  • 使用已存在的对象创建新的对象
CDate d1(1990, 1, 1);
CDate d2(d1);
  • 传值方式作为函数的参数
void FunTest(const CDate date)
{}
  • 传值方式作为函数的返回值
CDate FunTest()
{
CDate date;
return date;
}
三、析构函数
1.概念
  • 与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类的一些资源清理和汕尾工作。
class CArray
{p
ublic:
CArray(size_t capacity)
: _capacity(capacity)
{
_pData = ( int*)malloc(capacity*sizeof (int));
_size = 0;
} ~
CArray()
{
if (NULL != _pData)
{
free(_pData);
_pData = NULL;
}_
size = 0;
_capacity = 0;
}
private:
int* _pData;
size_t _size;
size_t _capacity;
};
2.特性
  • 析构函数在类名(即构造函数名)加上字符~。
  • 析构函数无参数无返回值。
  • 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
  • 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  • 注意析构函数体内并不是删除对象,而是做一些清理工作。
四、赋值运算符重载
1.概念

对于类类型的对象我们需要对‘=’重载,以完成类类型对象之间的赋值。

2.static成员

声明为static的类成员(成员数据或成员函数)称为类的静态成员。


  • 特性:
    (1)静态成员为所有类对象所共享,不属于某个具体的实例。
    (2)类静态成员即可用类名::静态成员或者对象.静态成员来访问。
    (3)类静态成员变量必须在类外定义,定义时不添加static关键字。
    (4)类的静态成员函数没有默认的this指针,因此在它里面不能使用任何非静态成员。
    (5)静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值,const修饰符等参数。
    这里写图片描述

注意:
(1)静态成员函数不可以调用非静态成员函数;
(2)非静态的成员函数可以调用静态的成员函数。

3.const修饰类成员

使用场景:
(1)const修饰形参,一般和引用同时使用;
(2)const修饰返回值;
(3)const修饰类数据成员,必须在构造函数的初始化列表中初始化;
(4)const修饰类成员函数,实际修饰隐含的this,表示在类中不可以对类的任何成员进行修改;
(5)在const修饰的成员函数中要对类的某个数据成员进行修改,该数据成员定义声明是必须加mutable关键字。

说明:
const对象不可以调用非const成员函数,非const成员函数可以调用const成员函数

五、取地址操作符重载
class CTest
{
public:
CTest* operator&()
{
return this ;
}
const CTest* operator &()const
{
return this ;
}
};

取址操作符重载函数返回值为该类型的指针,无参数。

  • inline函数
    以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
    1> inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联。
    2> inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联
    3> inline必须函数定义放在一起,才能成为内联函数,仅将inline放在声明前是不起作用的。
    4> 定义在类内的成员函数默认定义为内联函数。
六、const修饰的取地址操作符重载
const String* operator&() const
{
    return this;
}

函数后边的const表明在函数体中不能改变对象的成员,当然可以改变mutable变量。函数的返回值是指向常对象的指针。

练习题:编写String类的构造函数、析构函数、拷贝构造函数 、赋值运算符
  • 已知String类的原型为:
class String
{
public:
    String(const char* str = NULL);//普通构造函数
    String(const String& other);//拷贝构造函数
    ~String(void);//析构函数
    String& operator=(const String& other);//赋值函数
private:
    char* m_data;//用于保存字符串
};
  • 编写函数
//构造函数
String::String(const char* str)
{
    if (str == NULL)
    {
        m_data = new char[1];
        *m_data = '\0';
    }
    else
    {
        int length = strlen(str);
        m_data = new char[length + 1];
        strcpy(m_data, str);
    }
}

//拷贝构造函数
String::String(const String& other)
{
    int length = strlen(other.m_data);
    m_data = new char[length + 1];
    strcpy(m_data, other.m_data);
}

//析构函数
String::~String(void)
{
    delete[] m_data;
    //由于m_data是内部成员,也可以写成delete m_data
}

//赋值运算符重载
String& String::operator=(const String& other)
{
    //检查自赋值
    if (this == &other)
        return* this;
    //释放原有的内存资源
    delete[] m_data;
    //分配新的内存资源,并复制内容
    int length = strlen(other.m_data);
    m_data = new char[length + 1];
    strcpy(m_data, other.m_data);

    //返回本对象的引用
    return* this;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值