C++ 构造函数详解


前言

最近在复习C++的基础知识,在复习的时候才发现,对C++构造函数这方面的内容一直没有很清晰的了解,所以在此稍作记录。


一、构造函数

类的构造函数是类的一种特殊的成员函数,其任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。

构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。


二、构造函数分类

在C++当中,构造函数主要可以分为一下四类:

1.默认构造函数

Test();					//无参

2.初始化构造函数

Test(int x,int y);		//带参数,可初始化类内数据成员

3.复制(拷贝)构造函数

Test(const Test*temp);	//通过另一个类成员初始化该成员

其中若非自己单独声明,编译器都会给我们隐形构造这几类函数。

设有个Test类内有如下数据成员,之后的样例都基于此:

class Test{
private:
	int x;
	int y;
	int* p;
}

1.默认构造函数

因为此种构造函数无参,我们可以在其之后的内部进行赋值,当初始化语句如下时,将默认使用此构造函数:

//构造函数
Test() {
		x = 0;
		y = 0;
		p = new int(10);
		*p = 0;
}
//初始化方式
Test test1;

2.初始化构造函数

在这种构造函数当中,我们可以采用两种方式进行对类内成员的赋值,一种是列表初始化,而另一种是内部赋值,样例如下:

//构造函数(二者选一,不能共存)
Test(int a,int b) {
		x = 0;
		y = 0;
		
}
Test(int a, int b) :x(a), y(b) {}
//初始化方式
Test test1(10,20);

值得注意的是,C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。也就是说采用初始化列表的话,构造函数本体实际上不需要有任何操作,因此效率更高

同时凭借C++的重载特性,根据不同形参也可有多个构造函数

3.复制(拷贝)构造函数

该构造函数主要是使用一个已有的对象去初始化另一个对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中。样例如下:

//构造函数
Test(const Test& t)
{
		x = t.x;
		y = t.y;
		p = t.p;
}
//初始化方式
Test t1;
Test t2(t1);

但是运行此样例后我们会发现运行出错,其主要原因是浅拷贝深拷贝问题。

由于成员数据中含有指针,当我们简单的将指针等于另一个对象的指针后,当程序最后执行析构函数时,将对指针进行回收,但是由于两个指针都指向同一地址,而同一地址的两次析构,就会产生错误,所以正确样例如下:

Test(const Test& t)
{
		x = t.x;
		y = t.y;
		p = new int(10);
		*p=*(t.p);
}
//初始化方式
Test t1;
Test t2(t1);

在第二个样例中我们可以发现,对指针重新开辟了一块地址,而p=(t.p)这条语句成功将第二个对象指针所指内容赋值给第一个对象。
所以在这时,是有两个对象,两个指针指向不同地址,但其内容相同。
再次从输出直观体现这一差别:
错误样例
正确样例
一般在类成员数据中含有指针都要考虑深浅拷贝的问题。


特殊"构造"函数

在查找相关资料的时候,发现很多博文在构造函数中加入了一类为:赋值构造函数,主要声明方式如下:

//函数声明
Test& operator=(const Test& t)
{
		if (this == &t)
			return *this;
		delete p;
		x = t.x;
		y = t.y;
		p = new int;
		*p = *(t.p);
}
//初始化方式
Test t1(10,20);
Test t2;
t1=t2;

但自己总结后发现,这种操作只能称为赋值函数,而不是构造函数,因为当我们进行接下来的操作时:

Test t2=t1;

进行单步执行时发现,该语句只会执行上文的拷贝构造函数,而不是赋值函数。
但在构造函数的定义中,其是在类实例声明时即会调用,所以其并不能称为构造函数。
同时值得注意的是,在赋值函数中我们需要第一步首先判断是否是同一对象,防止循环引用,重复赋值等问题。


总结

在本文中,主要对C++中几类构造函数进行了介绍。
如文中出现纰漏,可在评论区和我交流。
同时指针操作需要记得释放内存,在此说明。

  • 10
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
移动构造函数C++11引入的一个新特性,通过移动构造函数,可以将一个对象的资源所有权转移到另一个对象,避免了不必要的资源拷贝,提高了程序的运行效率。 移动构造函数的定义如下: ```cpp class ClassA { public: ClassA(ClassA&& other) noexcept { // 移动构造函数的实现 } }; ``` 其中,`ClassA&&`表示移动构造函数的参数为右值引用。移动构造函数通常使用`noexcept`关键字进行修饰,表示该函数不会抛出异常。 移动构造函数的实现需要将另一个对象的资源转移到当前对象,并将另一个对象的资源置为无效。常见的实现方式是通过移动构造函数中的`std::move()`函数来完成。例如,对于一个包含动态分配内存的类: ```cpp class MyClass { public: MyClass(int n) : data(new int[n]), size(n) {} MyClass(MyClass&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; } ~MyClass() { delete[] data; } private: int* data; int size; }; ``` 在移动构造函数中,将另一个对象的指针和大小赋值给当前对象,并将另一个对象的指针置为nullptr,大小置为0,表示另一个对象的资源已经被移动到了当前对象。 使用移动构造函数可以大大提高程序的性能,特别是在涉及到大量的资源拷贝时。移动构造函数可以通过`std::move()`函数进行调用,例如: ```cpp MyClass a(10); MyClass b(std::move(a)); // 调用移动构造函数 ``` 在这个例子中,对象a的资源被移动到了对象b中,对象a的资源已经无效了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值