C++构造函数、析构函数、拷贝构造函数

构造函数

构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来主动调用它,构造函数会在对象被建立时自动被调用的。
作用就是用来处理对象的初始化操作。

注意事项:

①、构造函数的名字必须与类名同名,不能随意命名,这样的话才能让编译器认为该函数是构造函数,而不是类的普通成员函数;
②、构造函数不具有任何类型,不返回任何值,连 void 都不是;
③、构造函数不需要用户调用,也不应该被用户调用,它是对象建立的时候自动被系统调用,用来初始化刚刚建立的对象的;
④、如果用户没有定义自己的类的构造函数,那么系统会自动生成一个默认的构造函数,只不过该构造函数的函数体是空的,也就是什么都不做。

析构函数

析构函数也是一个在类中跟构造函数类似的特殊功能的成员函数。只不过它的作用是与构造函数相反,是在对象的生命周期结束的时候会被自动调用的。
在C++中析构函数的名字跟类名相同,并且前面带上一个取反的符号~,表达的意思也就是跟构造函数的过程相反。

析构函数的作用:
先拿构造函数来说话,构造函数是新建对象吗?回答:不是,而是在对象被创建出来之后自动被调用的,用来初始化相关信息的函数。
同理,析构函数也不是用来删除对象的,而是当对象被删除的时候自动会被调用的,用来做一些对象被删除之前的清理工作。只要对象的生命周期结束,那么程序就会自动执行析构函数来完成这个工作的。

以下几种情况会自动调用析构函数:

①、如果在一个函数中定义了一个局部变量的对象,那么当这个函数执行结束时也就是该变量对象生命周期结束的时候,所以析构函数会被自动调用;
②、全局变量或者static类型的变量,他们的生命周期一般是在程序退出的时候,这时候该对象的析构函数才会被调用;
③、如果是用new操作符动态的创建了一个对象,只有当用delete进行释放该对象的时候,析构函数才会被调用;

析构函数的特点:
析构函数不返回任何值,没有函数类型,也没有任何函数的参数。由于上面这些特点,所以析构函数不能被重载,所以说一个类可以有多个构造函数,但只能有一个析构函数

// 构造和析构小栗子:
#include <iostream>
#include <conio.h>
using namespace std;

class Cpoint{
public:
	static int value;
	static int num;
	Cpoint(int x,int y){
		xp=x;yp=y;
		value++;
		cout << "调用构造:" << value << endl;
	}

	~Cpoint(){num++; cout << "调用析构:" << num << endl;}

private:
	int xp,yp;
};

int Cpoint::value=0;
int Cpoint::num=0;
class CRect{
public:
	CRect(int x1,int x2):mpt1(x1,x2),mpt2(x1,x2) {cout << "调用构造\n";}
	~CRect(){cout << "调用析构\n";}
private:
	Cpoint mpt1,mpt2;
};

int main()
{
	{	// 不加这个{},因为下面为了显示使用这个system("pause");会暂停执行程序
		CRect p(10,20);
		cout << "Hello, world!" << endl;
	}

	// system("pause");
	getch();
	return 0;
}

拷贝构造函数

拷贝构造函数的特点:
①、也是构造函数,所以函数名字就是类名字,并且无返回值;
②、参数上有点特殊,参数是一般是本类的对象的引用;
③、如果类没有提供拷贝构造函数,那么编译器会默认生成一个拷贝构造函数,作用比较单一,只是简单的将成员变量的值进行复制过去而已。
拷贝构造函数实现的必要性:
类的成员变量中有一些无法进行赋值的,此时就需要自定义实现拷贝构造函数;
以下情况都会调用拷贝构造函数:

  1. 一个对象以值传递的方式传入函数体;
  2. 一个对象以值传递的方式从函数返回;
  3. 一个对象需要通过另外一个对象进行初始化。
#include <iostream>
using namespace std;
class CA
{
 public:
  CA(int b,char* cstr) // 构造
  {
   a=b;
   str=new char[b];
   strcpy(str,cstr);
  }
  CA(const CA& C)	// 拷贝构造
  {
   a=C.a;
   str=new char[a]; //深拷贝
   if(str!=0)
    strcpy(str,C.str);
  }
  void Show()
  {
   cout<<str<<endl;
  }
  ~CA()
  {
   delete str;
  }
 private:
  int a;
  char *str;
};
 
int main()
{
 CA A(10,"Hello!");  // 调用构造
 CA B=A;	// 调用拷贝构造
 B.Show();
 return 0;
} 

深拷贝和浅拷贝可以简单理解为:
如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

class Rect
{
public:
    Rect()      // 构造函数,p指向堆中分配的一空间
    {
        p = new int(100);
    }
    ~Rect()     // 析构函数,释放动态分配的空间
    {
        if(p != NULL)
        {
            delete p;
        }
    }
private:
    int *p;     // 一指针成员
};

int main()
{
    Rect rect1;
    Rect rect2(rect1);   // 复制对象
    return 0;
}

浅拷贝,只是将成员的值进行赋值,这时 rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间, 在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,出现错误。

深拷贝,对于对象中动态成员,重新动态分配空间,此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值