【C++】类成员函数分类及应用

本文介绍了C++中的类成员函数,包括构造函数(无参和带参)、析构函数、拷贝构造函数以及赋值运算符的概念和特点。构造函数用于初始化对象,析构函数在对象销毁前释放资源。拷贝构造函数处理对象的复制,未定义时产生浅拷贝,可能导致问题,如内存泄漏。赋值运算符重载用于自定义类型的赋值行为。文章强调了涉及资源管理时,拷贝构造函数和赋值运算符的必要实现,以避免浅拷贝带来的问题。

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

类成员函数分类

默认成员函数:当用户没有在类中显示定义时,编译器也会自动生成的成员函数。内置类型不处理,自定义类型调用它的默认构造。

构造函数

构造函数的名字与类名相同,创建类对象时由编译器自动调用。主要用于初始化对象(为各成员变量赋值)且在对象整个生命周期中只调用一次。

特点
1.由编译器自动调用
2.无返回值,也不写void
3.支持函数重载
4.函数名与类名相同
class Date
 {
  public:
      // 1.无参构造函数
      Date()
     {}
  
      // 2.带参构造函数
      Date(int year, int month, int day)
     {
          _year = year;
          _month = month;
          _day = day;
     }
  private:
      int _year;
      int _month;
      int _day;
 };
  
  void TestDate()
 {
      Date d1; // 调用无参构造函数
      Date d2(2015, 1, 1); // 调用带参的构造函数
 }

当用户没有显示定义构造函数时,编译器会自动生成一个默认的构造函数,进行初始化。默认构造函数生成时,对内置类型的类成员变量进行初始化时,其值为随机值;对自定义类型的类成员变量初始化时,编译器会调用该自定义类型成员的构造函数。

析构函数

析构函数的名字组成为~类名(),在对象销毁前由编译器自动调用。主要进行对象的清理工作。例如,free动态开辟的内存,防止内存泄漏等等。

特点
1.由编译器自动调用
2.无返回值,也不写void
3.不可以有参数,因此不支持函数重载
4.函数名~类名
class Date
{
public:
    ~Date()
    {
        //析构函数
    }
};

一个类只能有一个析构函数,若未显示定义,系统会自动生成默认析构函数,析构时,内置类型成员变量不处理,自定义类型成员变量会自动调用它的析构函数。

注:如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如

Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

拷贝构造函数

拷贝构造函数是函数名与类名相同,形参只有一个,是对类对象的引用(const修饰)。一般用于通过已存在的类对象初始化新的类对象、值传递的方式给函数参数传值、以值方式返回局部对象。

特征:
1. 拷贝构造函数是 构造函数的一个重载形式
2. 拷贝构造函数的 参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,
因为 会引发无穷递归调用
3. 若未显式定义,编译器会生成 默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
字节序完成拷贝,这种拷贝叫做浅拷贝,或者 值拷贝
浅拷贝和深拷贝

浅拷贝:进行简单的赋值操作

深拷贝:在堆中重新申请空间,进行拷贝操作

在没有手动定义拷贝构造函数时,编译器会默认生成拷贝构造函数,将类成员属性进行一个浅拷贝。而对于某些类,实现浅拷贝时会出现问题,如下:

class Person
{
public:
    Person()
    {
        cout << "Person 默认构造函数调用" << endl;
    }
    ~Person()
    {
        if (m_height)
        {
            delete m_height;
            m_height = NULL;
        }
        cout << "Person 析构函数调用" << endl;
    }
    Person(int age,int height)
    {
        m_age = age;
        m_height = new int(height);
        cout << "Person 有参构造函数调用" << endl;
    }

    int m_age;
    int* m_height;
};
//调用后,无法正常运行
void test1()
{
    Person m1(18,160);
    Person m2(m1);
    cout << "m2的身高是 " << *m2.m_height << endl;
}

因此我们需要手动实现构造函数。

Person(const Person& p)
   {
       m_age = p.m_age;
       m_height = new int(*p.m_height);
   }
总结:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
构造函数调用的典型场景
  1. 用一个定义好的类对象创建另一个类对象

class Person
{
public:
    Person()
    {
        cout << "Person 默认构造函数调用" << endl;
    }
    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }
    Person(int age)
    {
        m_age = age;
        cout << "Person 有参构造函数调用" << endl;
    }
    Person(const Person& p)
    {
        m_age = p.m_age;
        cout << "Person 拷贝构造函数调用" << endl;
    }

    int m_age;
};
void test1()
{
    Person m1(18);
    Person m2(m1);
    cout << "m2的年龄是 " << m2.m_age << endl;
}
  1. 值传递方式给函数参数传值

void Play(Person p)
{

}
void test2()
{
    Person m1;
    Play(m1);
}
  1. 值方式返回局部对象

Person test3()
{
    Person m;
    return m;
}
int main()
{
    Person p=test3();
    return 0;

}

赋值重载函数

C++中用户可以重定义或重载大部分内置的运算符。就能使用运算符进行自定义类型的运算。

函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
1.不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型参数
3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this
5. .* :: sizeof ?: . 注意以上5个运算符不能重载。(常用)
加法运算符重载

重载运算符一般可以有两种定义方式,可通过类成员函数/全局函数进行重载,以加号为例:

class Date
{
    Date operator+(const Date& d) //类成员函数进行重载
    {
        Date tmp;
        tmp.year=this->year+d.year;
        ....
        return tmp;
    }
private:
    int year;
    ...
};
Date operator+(const Date& d1,const Date& d2)  //全局函数进行重载
{
    ....
}
int main()
{
    Date d1;
    Date d2;
    Date d3=d1+d2;  
//Date d3=d1.operator(d2) 类成员函数进行重载本质
//Date d3=operator(d1,d2) 全局函数进行重载本质
    
}
自增/自减运算符重载

分为前置和后置两种,区别是前置返回++/--之后的值,后置是++/--之后返回原来的值

// 前置++:返回+1之后的结果
// this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
 {
 _day += 1;
 return *this;
 }
// 后置++:
// C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
// 后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1
// 而temp是临时对象,因此只能以值的方式返回,不能返回引用
 Date operator++(int)
 {
     Date temp(*this);
     _day += 1;
     return temp;
 }
赋值运算符重载(=)
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
不支持通过全局函数进行运算符重载,会与编译器在类中生成的 默认赋值运算符重载冲突了
Date& operator=(const Date& d)
{
    if(this != &d)
     {
          _year = d._year;
          _month = d._month;
          _day = d._day;
     }
     return *this;
}

和拷贝构造函数的原理类似:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

关系运算符重载

C++ 语言支持各种关系运算符( < 、 > 、 <= 、 >= 、 == 等等),它们可用于比较 C++ 内置的数据类型。

返回值类型:bool

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值