构造函数和析构函数

构造函数

在创建C++对象实例化后,其内部数据是随机值,对于C而言,通常采用初始化函数进行初始化,而在C++中,可以认为初始化工作交给了构造函数完成。
关于构造函数必须要了解的有:

  1. 构造函数的函数名必须和class类名一样,可以带形参也可以不带,但不能有返回值,如同人一生只能出生一次,对于一个实例而言,一生只能构造一次 。

  2. 构造函数可以重载 ,即构造函数的参数可以不一样 。创建对象时根据传递的实参来判断调用哪一个构造函数。但是如果构造函数参数中有默认值,那么将无法确定哪个函数作为初始化,不能重载。

  3. 构造函数不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。

  4. 允许使用一个对象初始化另一个对象,这种方式称为拷贝构造方法。test t3(t1);(详见代码)。值得注意的是,拷贝方法在创建对象时并不会调用构造函数。

默认构造函数

如果用户自己没有定义构造函数,那么编译器会自动生成一个默认的构造函数,只是这个构造函数的函数体是空的,也没有形参,也不执行任何操作。但用户一旦定义,则系统不在默认构造函数,因此,在实例化对象时要注意。默认生成的构造函数如下:

test(){}

析构函数

创建对象后需要对对象做“销毁”,C++中析构函数担当了这一角色。与构造函数相比,析构函数的函数名必须是”~类名“(~test())的形式。析构函数没有返回值,不能显式调用,而是在销毁对象时自动执行。同构造函数类似,如果用户没有定义,编译器会自动生成一个默认的析构函数。

析构函数的执行时机

析构函数在对象被销毁时调用,而对象的销毁时机与它所在的内存区域有关。

在所有函数之外创建的对象是全局对象,它和全局变量类似,位于内存分区中的全局数据区,程序在结束执行时会调用这些对象的析构函数。

在函数内部创建的对象是局部对象,它和局部变量类似,位于栈区,函数执行结束时会调用这些对象的析构函数。

new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。

#include <iostream>
#include <string>
using namespace std;

class Demo{
public:
    Demo(string s);
    ~Demo();
private:
    string m_s;
};
Demo::Demo(string s): m_s(s){ }
Demo::~Demo(){ cout<<m_s<<endl; }

void func(){
    //局部对象
    Demo obj1("1");
}

//全局对象
Demo obj2("2");

int main(){
    //局部对象
    Demo obj3("3");
    //new创建的对象
    Demo *pobj4 = new Demo("4");
    func();
    cout<<"main"<<endl;
  
    return 0;
}
//运行结果:
//1
//main
//3
//2

this指针

this指针是 C++ 中的一个关键字,也是一个默认存在的 const 指针,它指向当前对象。this 只能用在类的内部,通过 this 可以访问类的所有成员,包括 private、protected、public 属性的。

几点注意:
this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。 this
只能在成员函数内部使用,用在其他地方没有意义,也是非法的。 只有当对象被创建后 this 才有意义,因此不能在 static
成员函数中使用(后续会讲到 static 成员)。
this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。

this 作为隐式形参,本质上是成员函数的局部变量,所以只能用在成员函数的内部,并且只有在通过对象调用成员函数时才给 this 赋值。

在*《C++函数编译原理和成员函数的实现》*一节中讲到

成员函数最终被编译成与对象无关的普通函数,除了成员变量,会丢失所有信息,所以编译时要在成员函数中添加一个额外的参数,把当前对象的首地址传入,以此来关联成员函数和成员变量。这个额外的参数,实际上就是this,它是成员函数和成员变量关联的桥梁。

int count=1;
class test{
	public:
		int pu_a;
		test(int data){//构造函数1
			a=data;
			pu_a=data; 
			cout<<"t1  this的地址:" <<this<<endl;
		}
		test(){
			cout<<"t2 this的地址:" <<this<<endl;
		}
		//析构函数<收尸 >,释放对象而非空间 
		~test()
			cout<<"this指针位置:"<<this<<' '<<count++<<endl;
		}
		//拷贝构造方法(使用对象初始化对象);在对象作为函数的值传递时常用到 
		//void fun(test t1) ;
		//test fun(test t2);(构造无名临时对象返回,即返回时也会调用拷贝方法)
		test(const test & t){//函数名与类相同,注意参数 ,语法要求引用传递 ,不然会递归下去 
			a=t.a;
			cout<<"拷贝构造this地址"<<this<<endl;
		}
		
	private:
		int a;
};
test fun(test t){
	cout<<"函数_拷贝构造函数调用"<<endl; 
}
int main(){
	test t1(1),t2; //两者的构造函数不同 
	test t3(t1);//等价于test t3=t1。使用t1构造t3,不会调用构造函数 ,而是拷贝构造方法,但会调用析构函数 
	test t4(t3); 
	cout<<"初始化值: "<<t1.pu_a<<endl;
	cout<<"===程序==="<<endl; 
	//t1  this的地址:0x6bfee8
	//t2 this的地址:0x6bfee0
	//拷贝构造this地址0x6bfed8
	//this指针位置:0x6bfed8 1
	//this指针位置:0x6bfee0 2
	//this指针位置:0x6bfee8 3
	//注意地址,在栈上 
	fun(t1); 
	//t1  this的地址:0x6bfed8
	//t2 this的地址:0x6bfed0
	//拷贝构造this地址0x6bfec8
	//拷贝构造this地址0x6bfec0
	//初始化值: 1
	//===程序===
	//拷贝构造this地址0x6bfee8
	//函数_拷贝构造函数调用
	//this指针位置:0x6bfee0 1
	//this指针位置:0x6bfee8 2
	//this指针位置:0x6bfec0 3
	//this指针位置:0x6bfec8 4
	//this指针位置:0x6bfed0 5
	//this指针位置:0x6bfed8 6
	其中test fun(test t)会调用两次拷贝,一次传值,一次返回 
	return 0;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值