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

  1. 构造函数(constructor):在实例对象时,系统自动调用,用来初始化对象的数据成员

      构造函数声明语法:
      类名(参数列表);
      构造函数注意点:

  •  函数名必须是类名
  • 无返回值类型
  • 不同参数列表
  • 可以是私有
  • 一个类可以存在多个不同形式的构造函数(构造函数可以重载)
#include <iostream>
#include <string.h>
using namespace std;
class  Computer
{
public:	
	//定义默认值构造函数
    //减少其他形式构造函数定义
	Computer(int _hz=123,int _mem=1024)
	{
		cpu_hz=_hz;
		memory=_mem;
	}
        //上面的构造函数也可以写成参数列表初始化的形式
	Computer(int _hz=123,int _mem=1024):cpu_hz(_hz),memory(_mem)
	{
		//cpu_hz=_hz;
		//memory=_mem;
	}
	void  printcomputer()
	{
		cout<<computer_kind_name<<"\t"<<cpu_num<<'\t'<<cpu_hz<<"\t"<<memory<<endl;
	}
private
	int   cpu_hz;//c11标志支持定义成员变量时赋值,但是一般不这样赋值
	int   memory;
};
/*类里面的函数实现可以在外面,模式如下:
//类的成员函数定义
Computer::Computer(int _hz=123,int _mem=1024):cpu_hz(_hz),memory(_mem)
{
	cout<<"constructor"<<endl;
}
//类的成员函数定义
void  Computer::printcomputer()
{
	cout<<cpu_hz<<"\t"<<memory<<endl;
}
*/
int main(int argc, char const *argv[])
{
	Computer  c1;//构造一个对象,如果没有自己实现构造函数调用的是无参构造函数,这里是使用的默认构造参数
        //一般类中存在一个无参构造函数,只要定义构造函数,默认构造函数不存在
	Computer  c2("1111");
	c1.printcomputer();
	c2.printcomputer();

        Computer &c3=c1 ;//引用
        Computer  *c4=new Computer;	//new Computer 动态创建匿名对象
        Computer  *c5=&c1;//c5是一个指针
        Computer  *c6=new Computer(1,2);//new Computer(1,2) 动态创建匿名对象
        Computer  *c7=new Computer[2];//new Computer[2]  动态创建2个匿名对象
        Computer  c8[2];//对象数组
	Computer* c9[2];//指针数组
	Computer*  (*c10)[2];//数组指针
	return 0;
}

        2.拷贝构造函数(复制构造函数):构造新对象时,用一个对象作为引用参数.复制参数对象的成员值
          类存在一个默认拷贝构造函数

           调用拷贝构造函数:

  • 对象初始化新对象
  • 对象作为函数形参,并且是值传递
  • 返回值类型是对象

      类中都存在一个赋值函数
      void   operator =(A  & obj)


#include  <iostream>
#include  <stdio.h>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int _a)
	{
		a=_a;
	}
	//引用类型的参数
	A(const A&  obj)
	{
		cout<<"copy constructor"<<endl;
		a=obj.a;
	}
	//赋值函数
	void   operator =( A  & obj)
	{
		cout<<"operator ="<<endl;
		a=obj.a;
	}

	void  printa()
	{
		cout<<a<<endl;
	}
private:
	int a;
};
A  fun()
{
	static A a(4);//静态变量没有存在栈空间
	//A a(5);//这样写是存在问题的,执行return后栈空间被释放了,不能返回任何东西
	return a;
}
int main(int argc, char const *argv[])
{
	A a1(3);
	a1.printa();

	A a2(a1);//这里调用的就是拷贝构造函数,参数是另一个对象
	A a3 = a1;//这里也是调用的拷贝构造函数。

	A a4;
	a4 = a1;//这两句话才是调用的赋值函数void   operator =( A  & obj)

	fun();//通过程序执行结果我们可以发现:
		  //当函数的返回值是一个对象的时候,返回对象的时候调用了拷贝构造函数。
	cout<<"----"<<endl;
	A ret=fun();

	const  A& ret2=fun();//fun() 返回时创建一个临时对象,把函数内部对象拷贝给临时对象,并且临时对象不可以修改
	return 0;
}
  • 拷贝分为深拷贝和浅拷贝

       浅拷贝:只单纯的拷贝对象成员值

       深拷贝:拷贝对象成员值,还拷贝成员指向其它值

#include  <iostream>
#include  <stdio.h>
using namespace std;

class A
{
public:
	A()
	{
		p=new int[3];
	}
	/*//浅拷贝
	A(const  A&  obj)
	{
		p=obj.p;
		cout<<"copy constructor"<<endl;
	}*/

	//定义深拷贝
	A(const A & obj)
	{
		p=new int[3];//也就是在调用拷贝构造函数时,需要重新给对象分配内存,
                             //将被拷贝对 象内存里面的东西放在新对象里面
		//不然就是浅拷贝---> 直接把被拷贝对象的地址赋给了新的对象,那么在程序结束后
		//调用析构函数会多次释放同一个地址而报错。
		int i;
		for(i=0;i<3;i++)
		{
			p[i]=obj.p[i];
		}
	}

	~A()//析构函数
	{
		//释放语句
		if(p!=NULL)
		{
			delete p;
		    p=NULL;
		}		
	}
private:
	int *p;
};
int main(int argc, char const *argv[])
{
	A a1;
	A a2(a1);//浅拷贝,在对象释放时,执行析构函数,析构函数释放的是同一个堆空间,出现错误
	return 0;
}

     3.析构函数

      定义析构函数:
      ~类名()
     析构函数定义注意点:

  • 函数名是~类名
  • 无返回值类型
  • 无参
  • 一个类中有且只能有一个析构函数.默认存在析构函数

     如果没有对象释放,系统不会调用析构函数

    对象构造与析构顺序:
    先构造的最后析构


#include  <iostream>
#include  <stdio.h>
using namespace std;
class A
{
public:
	A()
	{
		cout<<"constructor"<<endl;
		p=new int[3];
	}
	//定义析构函数
	~A()
	{
		cout<<"disconstructor"<<endl;
		//释放语句
		delete p;
		p=NULL;
	}
private:
	int *p;
};
void   fun()
{
	int i;
	for(i=0;i<10;i++)
	{
		static A  a1;//静态局部变量只初始化一次
	}
}
int main(int argc, char const *argv[])
{
	A a1;

	A *a3=new A;
	//必须手动释放对象,否则析构函数不能调用
	delete a3;
	a3=NULL;

	fun();//只调用一次析构函数

	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37579906/article/details/81834956