学习->C++篇二:类的默认成员函数

目录

1. 类的6个默认成员函数 

2. 构造函数

3. 析构函数

4. 拷贝构造函数

深浅拷贝

​5. 赋值运算符重载

运算符重载:

赋值运算符的重载

前置++和后置++

​6. const成员函数

7. 取地址及const取地址操作符重载


1. 类的6个默认成员函数 

        对于类的成员函数,有6个重要的函数,即使没有显示定义,编译器也很会默认生成这6个函数,根据它们的任务,可分成三种:

初始化和清理任务:

        构造函数->完成初始化工作

        析构函数->完成资源的清理工作

拷贝和复制任务:

        拷贝构造函数->用同类对象初始化创建对象

        赋值重载函数->将一个对象赋值给另一对象

取地址重载:

        两个&运算符重载函数->普通对象和const对象的取地址

2. 构造函数

        当类的对象创建时,就会调用构造函数来初始化对象的数据成员,但是构造函数的任务不是为对象开辟空间,而是初始化对象。

构造函数特性:

1. 函数名与类名相同
2. 无返回值,也不写void
3. 构造函数不用显式调用(对象实例化时编译器自动调用对应的构造函数初始化对象)
4. 构造函数可以重载(类可有多个构造函数)

5.构造函数不能被声明成const(初始化过程后对象才有常属性)

        当用户未显示定义构造函数时,编译器会合成一个默认的无参构造函数,只要用户显示了一个便不生成。这个合成的默认构造函数会默认初始化内置类型的成员(如果有默认值,则按默认值初始化,C++11支持的),对于自定义类型的成员则去调用它们的默认构造函数。

注意:内置类型就是C++语言提供的数据类型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型。

当不传递参数去创建对象时,会调用默认构造函数,显然构造函数有且只能有一个。

有以下三种:

1.我们没定义构造函数,编译器合成的默认函数。

2.我们定义的全缺省构造函数

3.我们定义的无参构造函数。

如果我们定义了两个,调用时就会发生歧义。

虽然编译器会合成默认构造函数,更多时候则要自己写,其一,我们如果自己定义了构造函数,没有定义构造函数,类就没有默认构造函数。其二,编译器的默认构造函数初始化的值是默认的,可能不是我们想要的。其三,如果类的自定义类型的成员没有默认构造函数,编译器也无法合成默认构造函数。

3. 析构函数

        与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

析构函数特性:

1.函数名:类名+~

2.无返回值,也不写viod

3.一个类只能有一个析构函数,故不能重载,若不显式定义,编译器会默认合成一个。

4.不可显式调用,对象生命周期结束,编译器自动调用。

        编译器合成的析构函数,对于内置类型的成员不处理,对于自定义类型的成员也去调用它的析构函数,但与编译器合成的默认构造函数调用顺序相反:如下例

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

4. 拷贝构造函数

有时候需要用已存在的对象来拷贝生成一份新的对象,这时拷贝构造函数就派上用场了。

拷贝构造函数特征:

1.拷贝构造函数也是构造函数,它是构造函数的重载形式。

2.只有一个形参且为同类对象的引用(一般为const修饰),不能是传值的方式,不然传参时将无穷递归调用该函数。

3.若未显式定义,编译器将默认生成一个浅拷贝的默认构造函数(按字节序去拷贝)

4.若类中有申请资源,用编译器合成的默认拷贝构造函数,完成的是浅拷贝,不能满足需求,还会引发问题,这时应当自己定义。 

深浅拷贝

        例如成员指针变量指向一块堆区的空间,当调用默认的拷贝构造函数时,完成的是浅拷贝,生成的新的对象的成员指针变量于原来的指针变量一样,也就是指向了同一块堆区空间,这样当修改新对象时,原来的对象也将发生改变,当析构函数释放这一堆区空间时,两个对象将分别释放各自指针指向的堆区空间,导致两次释放的问题。

        要解决浅拷贝引发的问题,就要进行深拷贝,重新开辟新的对象的指针指向的堆区空间,再将原来的对象指针指向的内容拷贝进来,这样就能解决浅拷贝的两个问题。

示意图:浅拷贝

 深拷贝:


5. 赋值运算符重载

运算符重载:

为增强代码的可读性,C++引入运算符重载,让自定义类型也能进行运算。

运算符重载特征:

1.函数原型是:返回值类型 operator操作符(参数列表),与普通函数类似

2.函数名是operator操作符,也能函数重载(函数重载和运算符重载不是一回事)

3.不能用别的符号进行运算符重载,只能用除.*  ::  sizeof  ?:  .五个运算符以外的运算符来重载。

4.不能改变内置类型操作符的含义,例如整形的加减的含义,不能改变。

5.与普通类的成员函数一个,作为类的成员函数时,第一个参数默认为隐藏的this指针。

        倘若要访问类的私有成员,一般重载为类的公有成员函数;或者重载成全局函数,再作为类的友元函数去访问,但这样破坏了封装。但是因为成员函数首参数隐藏this指针的问题,让重载的二元操作符的左操作数固定为this,有时不太合乎需求,就重载成全局函数。

赋值运算符的重载

        赋值运算符的重载是特殊的,它只能重载成类的成员函数。因为倘若重载成全局函数,会与类内默认生成的赋值运算符重载冲突,与拷贝构造函数类似,默认生成的赋值运算符重载完成的是浅拷贝,倘若会产生问题,就当自己定义一个深拷贝的赋值运算符重载。

        如果用户没有显式实现时,编译器会生成一个默认赋值运算符重载,在调用该函数时,类的内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

注意:用 = 去初始化对象,调用的是拷贝构造函数而不是进行赋值,赋值运算符运用于两个已经存在的对象。

前置++和后置++

        前置后置含义不同的一元操作符的重载,前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载,C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递,以区分前置和后置。

        因为前置++要返回对象++之后的值,为了提高效率,通常用引用返回,故前置++返回的是原对象的别名,能++++对象,这样调用。而后者++要返回的是对象++之前的值,因为实现后置++函数时,对象须在返回前++,故通过临时对象拷贝原对象,++原对象,再返回临时对象的方式实现,故进行值返回,返回临时对象的引用会发生越界访问的问题,因为临时对象返回值后就析构了。

例如:

#include<iostream>
using namespace std;
class A {
public:
	A& operator++()
	{
		++a;
		return *this;
	}
	A operator++(int)
	{
		A tmp=A(*this);
		++a;
		return tmp;
	}
	void print()
	{
		cout << "a==" << a<<endl;
	}
private:
	int a=0;
};

int main() 
{
	A a1;
	A a2;
	++++a1;
	A a3=a2++;
	a1.print();
	a2.print();
	a3.print();
	return 0;
}

输出:


6. const成员函数

 这个成员函数不是返回值是const修饰的,而是this指针被const修饰,这样一来this指向的对象不可改变,但是this是隐藏的参数,C++将const放在函数名和()的后面,例如:

        假设类名是A,对于A类的普通对象,this指针类型是A*const this,如果用它去调用const成员函数,原本A是可读可写的权限,现在变成只读的权限,权限缩小了,可以调用,倘若是一个常对象(也就是const修饰的对象),那么它的this指针类型就是const  A *const this,常对象去调用const成员函数没什么问题,因为参数this的类型一模一样,若调用非const成员函数就会发生权限放大的问题,例如:当const对象a4调用非const成员函数print时编译器报错了>>

总之,常对象只能调用const成员函数,调用const成员函数就不能修改this指向的对象。


7. 取地址及const取地址操作符重载

当定义了类后,如果实例化了普通对象和const对象,对它们使用 & 取地址便能获得对象的地址,例如:

 事实上是编译器默认生成了两个&取地址操作符重载函数(两个函数构成函数重载),因为const对象不能调用非const成员函数,所以各生成了一个,以适应需求,用户也可根据想实现的功能显示去写,例如:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值