C++类和对象:默认成员函数(2)

目录

拷贝构造函数(定义、对拷贝构造的第一个参数必须是对与自身同类型的类的引用的解释、函数对不同类型的处理)

重载运算符函数(定义、格式、使用演示)

赋值运算符重载函数(定义、格式、函数对不同类型的处理、使用演示)


拷贝构造函数

<1>定义:也是用来初始化的默认成员函数,是构造函数的重载,但与构造函数不同的是,它是用一个同类型的对象去初始化另一个对象,而且传值传参和传值返回都会用到拷贝构造。

<2>拷贝构造的第一个参数必须是对与自身同类型的类的引用(以一个日期类的拷贝构造为例,格式为--> Date(const Date& d)),那为什么参数是传引用而不是传值呢?这是因为传值会造成无穷递归问题。每次调用拷贝构造都要传值传参,而传值传参又需要调用拷贝构造,于是就不断递归下去了。在参数前加上const是因为避免传过来的对象被修改,增强代码的健壮性。(注意:拷⻉构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引⽤,后⾯的参数必须有缺省值)

<3>对不同类型的处理:对⾃定义类型成员变量会调⽤他的拷⻉构造,对内置类型进行浅拷贝(就是一个字节一个字节地拷贝,指向同一块空间),当涉及在堆上开辟空间时(比如malloc出来的数组)会引发两个问题 :空间会被析构两次,并且一个对象被修改就会影响另一个。所以,这时候就需要自己显示实现拷贝构造(小技巧:需要显示实现析构时就必须显示实现拷贝构造)

注意:函数传引用返回时要注意返回值是否被销毁,否则就像野指针一样造成“野引用”。下面举一个野引用的例子:

class Date
{
   //...
};
Date& Func()
{
   Date tmp;//创建临时对象tmp
   return tmp;//tmp出了函数就被销毁,不能返回tmp的引用
}

重载运算符函数

<1>定义:就是当运算符被⽤于类类型的对象时,给操作符一个新的定义,让自定义类型也能进行加减乘除等运算。

<2>格式:函数名是由operator和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。

<3>重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多,但是当它作为成员函数时,它的第⼀个运算对象默认传给隐式的this指针,参数⽐运算对象少⼀个。

注意:<1>  .*   ::   sizeof  ?:   .  这5个操作符不能重载。

           <2>重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。(演示-->Date operator++(int))

下面演示一下“==”的重载运算符函数:

class Date
{
public:
   bool operator==(const Date& d)//"=="的重载
   {
       return _year == d._year
       && _month == d._month
       && _day == d._day;
   }
private:
   int _year;
   int _month;
   int _day;
}

赋值运算符重载函数

<1>定义:将一个已实例化的对象赋值给另一个已实例化的对象。注意与拷贝构造区分,赋值重载的两个对象都是已经存在的,而拷贝构造是⼀个对象拷⻉初始化给另⼀个要创建的对象。

<2>格式:函数名是由operator和“=”共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。返回类型建议写成当前类类型的引用,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋值场景。参数建议写成const 当前类类型引⽤,可以减少拷⻉。(注意:赋值重载规定必须重载为成员函数)

<3>对不同类型的处理:对⾃定义类型成员变量会调⽤他的赋值重载,对内置类型进行浅拷贝(就是一个字节一个字节地拷贝,指向同一块空间),当涉及在堆上开辟空间时(比如malloc出来的数组)会引发两个问题 :空间会被析构两次,并且一个对象被修改就会影响另一个。所以,这时候就需要自己显示实现赋值重载(小技巧:需要显示实现析构时就必须显示实现赋值重载)

下面显示实现一下日期类的赋值重载:

你可能感兴趣的:(c++)