C++类与对象之构造函数,拷贝构造函数,析构函数浅谈

本期我们来聊一聊类与对象的一个重要内容,构造函数,拷贝构造和析构函数的定义和使用。其实,就算程序员自己不编写这三个函数,C++编译器也会有默认的这三个函数,但是由于有时候默认的这三个函数不能满足我们的需求,所以我们需要自行编写这三个函数。

1.构造函数

首先我们要先知道什么叫构造函数,构造函数用于在进行类与对象编程时候使用的一个函数,它的作用正常我们用来初始化类中的各个成员数据,构造函数又分为两种,无参构造函数和有参构造函数,这两种很好理解,第一种就是参数列表里没有参数,第二种则是参数列表中有参数,我们首先先来学习一下关于构造函数的语法:

class 类名

{

public:

          类名(参数列表)

         {

                      函数体...

         }

private:

}

没错,构造函数的函数名是和类名相同的,括号里面就是我们的形参列表,可以没有参数,也可以有参数,注意:构造函数是没有返回值的,所以再写函数体时我们是不需要return的。

下面举一个具体的例子:

class Person
{
public:
	Person(int age,string name)
	{
		m_Age = age;
		m_name = name;
	}
private:
	int m_Age;
	string m_name;
};

这里我们就利用了有参构造函数对类内的成员进行了一个初始化操作,其实,在函数体的内容过多时,我们也可以在类外实现构造函数,这里就不在赘述,事实上,C++还提供了一种语法可以对多个成员进行初始化的语法——初始化列表,例如,上述代码可以改为以下形式:

class Person
{
public:
	Person(int age, string name) :m_Age(age), m_name(name)
	{

	}
private:
	int m_Age;
	string m_name;
};

这与上述代码功能相同

其语法为:    类名(形参列表):内嵌成员1(参数1),内嵌成员2(参数2)...{ }

利用这种方式我们可以直接将成员数据进行初始化并且可以在花括号里面进行其他函数功能的实现。

讲完了定义,我们提一下怎么调用构造函数,事实上,我们不用自己去调用构造函数,因为构造函数在对象创建时就会自行被调用,所以我们说构造函数会自行调用,但是里面有些细节需要注意,如果时有参构造函数,在创建对象时需要传入参数,否则编译器会报错,如果你的参数有了默认值,则不需要在创建对象时在另外传入参数,具体实现看下列代码:

int main()
{
    Person p(18,"张三");
    return 0;
}

这样我们就完成了一个对人类具体对象的创建,并且这个对象已经初始化好了年龄和姓名的两个属性,我们可以直接使用。

2.拷贝构造函数

接下来我们来谈谈拷贝构造函数的定义与使用,拷贝构造函数有些教科书上又叫做复制构造函数,但是只是名字上的不同而已,那么,拷贝构造函数有什么用途呢?大家可以想想,在生活中,我们有时候需要用已经有的文件去复制新的文件使用,拷贝构造函数实现的就是这个功能,拷贝构造函数的语法如下:

类名 (const 类名

&  对象名)

{

      函数体
}

我们可以看到拷贝构造函数的函数名也是类名,但是不同的时括号内必须要有参数,这个参数就是你要传进来的对象的引用,与构造函数一样,拷贝构造函数也是没有返回值的,这点小伙伴们要记牢,关于拷贝构造函数的定义具体实现,看下面代码:

class Person
{
public:
	Person(int age, string name) :m_Age(age), m_name(m_name)
	{

	}
	Person(const Person& p)
	{
		m_Age = p.m_Age;
		m_name = p.m_name;
	}
private:
	int m_Age;
	string m_name;
};

在这里我就写好了一个拷贝构造函数了,这样,当我们要建立一个新对象时,我们就可以利用已经有的对象去对新的对象进行初始化,代码如下:

class Person
{
public:
	Person(int age, string name) :m_Age(age), m_name(m_name)
	{

	}
	Person(const Person& p)
	{
		m_Age = p.m_Age;
		m_name = p.m_name;
	}
private:
	int m_Age;
	string m_name;
};
int main()
{
	Person p1(18, "张三");
	Person p2(p1);
	return 0;
}

可以看到,这里我就利用p1对新对象p2进行初始化,这里又涉及到了拷贝构造函数调用的方法,一共有三种方法,但是我在这里就说一种最常用的,就是我上面代码中所写的,这种方法叫做括号法,很简单,只要在创建新对象时用括号把已经有的对象括住,这样就可以调用拷贝构造函数,此时,p2中的属性与p1中的就会完全一样,达到的拷贝的目的。

接下来我们需要知道程序什么时候会调用拷贝构造函数。

第一点:就是我们上面代码所演示的那样,当我们用一个已经存在的对象去初始化另一个新创建的对象时,程序就会调用拷贝构造函数。

第二点:当函数的形参使用值传递的方式传入对象时,程序也会自己调用拷贝构造函数,例如:

class Person
{
public:
	Person(int age, string name) :m_Age(age), m_name(name){ }
	Person(const Person& p)
	{
		m_Age = p.m_Age;
		m_name = p.m_name;
		cout << "拷贝函数调用" << endl;
	}
private:
	int m_Age;
	string m_name;
};

void test(Person p)
{
	Person p1(p);
}
int main()
{
	Person p(18,"张三");
	test(p);
	return 0;
}

我们可以看到test这个函数,它的参数是Person类的一个对象,并且是用值传递的传入对象的,这个时候程序就会自己调用拷贝构造函数,事实上,我这边的程序中,test函数实际上里面调用了两次拷贝构造函数,因为在传入参数时调用了一次,我在函数体又利用临时对象初始化了临时对象p1,所以这一程序的运行结果为:

 3.函数返回值为类的对象时,并且是以值返回而非引用,那么在调用函数的时候也会自动调用拷贝构造函数,具体案例如下代码:

class Person
{
public:
	Person(int age, string name) :m_Age(age), m_name(name){ }
	Person(const Person& p)
	{
		m_Age = p.m_Age;
		m_name = p.m_name;
		cout << "拷贝函数调用" << endl;
	}
private:
	int m_Age;
	string m_name;
};
Person test01()
{
	Person temp(18, "张三");
	return temp;
}
int main()
{
	test01();
	
	return 0;
}

这里我写了一个以类的对象为返回值的函数,我们知道,临时对象在函数调用结束的时候就会自动消亡,那么为什么这个函数还会调用拷贝构造函数呢,事实上,在以值的方式返回一个对象时,编译器会自己创建一个无名的临时对象,那么这个时候就会调用拷贝构造函数了,所以上述代码的运行结果为:

 以上就是关于拷贝构造函数的定义以及它的调用时机的相关内容。

3.析构函数

我们知道的,自然界的万物都有生有灭,对象也不例外,析构函数是一个与构造函数相反的存在,

构造函数用于初始化一个新的对象,而析构函数用于销毁使用结束的对象。

先来学习关于析构函数的语法

~类名()

{

           函数体
}

这个函数与上面两个函数有些相似,函数名都是类名,但是与之不同的是析构函数在定义时前面要加上一个 “ ~ ”  符号,并且析构函数不可以有参数列表,这时与构造函数和拷贝构造函数不同的地方,我们前面说过,我们就算不编写这三个函数,C++编译器也会为我们提供这些函数,这些函数的函数体都为空,这就是函数的空实现。

以上就是本期关于构造函数,拷贝构造函数,析构函数的浅谈,读者在看完文章之后可以自己多多练习,去体会其中的关系和用法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值