第4节课:9.3:构造析构

第4节课:9.3:构造析构

一、构造函数

1.构造函数是什么:

给类数据成员赋值的,也就是或初始化类的对象

(如果为私有数据成员,不像结构体那样可以在定义的时候直接给值初始化)

2.构造函数的定义方法:Stu()

1.名字与类名相同

2.没有返回值类型(void)也不行

3.函数体为赋值逻辑

4.有参数列表(对外接口)

3.使用方法:

1.调用时机:自动调用

在定义类的对象的时候,或者动态开辟的时候

class Stu
{
	int num;
public:
	int a;
	Stu();
};

Stu::Stu()
{
	num = 1;
	a = 2;
}
int main()
{
	Stu stu;
	Stu * p = new Stu;//可以打断点调试
	return 0;
}
2.构造函数的重载(无参构造和带参构造)

1.重载的参数列表不同,函数体不同

2.注意:当类中定义了带参构造函数后,不可以Stu stu;定义会报错,不会调用系统默认的构造函数,系统不会提供默认构造函数了

也就是说不能用默认的构造方式初始化对象(系统的默认构造函数什么也不做)

class Stu
{
	int num;
public:
	int a;
	Stu();
    Stu(int i);
};
Stu::Stu()//无参构造函数
{
	num = 1;
	a = 2;
}
Stu::Stu(int i)//带参构造函数
{
	num = 1;
	a = 2;
}
int main()
{
	Stu stu;//调用无参构造函数
	Stu stu2(1);//调用带参构造函数
    Stu * p = new Stu(1);//调用带参构造函数
	return 0;
}
//注意:当类中定义了带参构造函数后,不可以Stu stu;会报错,不会调用系统默认的构造函数

二、拷贝构造函数

1.是什么?

用一个对象给另外一个对象初始化,或者是实参和形参(形参为类的对象)结合的时候

2.定义?(const Stu& other)

是一种特殊的函数,函数名与类名相同,参数列表(const Stu& other)只能传引用,不能传值不然死循环,报错

3.使用:

1.系统默认的拷贝构造函数

系统有默认的拷贝构造函数,隐式调用但是与默认的构造函数不同的是,形参列表不同(不是什么都不做)

默认拷贝是浅拷贝。(也就是说两个对象从数据成员指向同一块内存区域)

举个栗子:

class Stu
{
	int num;
	int a;
	char* name;
       public:
	Stu(int i);
}
Stu::Stu(int i)
{
	num = i;
	a = 2;
	name = "chi";
}
int main()
{
    Stu stu1(1);
    Stu stu2(stu1);//调用默认的,stu2的值与stu1的值一模一样
}
2.浅拷贝和深拷贝:什么时候需要重写拷贝构造?

从上面的例子知道:stu1和stu2的name的指针的值是一样的

#include <stdio.h>
#include <string>
using std::string;
//#include <string>


class Stu
{
	int num;
	int a;
	char* name;
public:
	Stu(int i);
	void print()
	{
		printf("%d\n",num);
		printf("%s\n",name);
	}
	//拷贝
	Stu(const Stu& other);
};

Stu::Stu(int i)
{
	num = i;
	a = 2;
	name = "chi";
}

Stu::Stu(const Stu& other)
{
	//深层构造
	a = other.a;
	num = other.num;
	//name = other.name;
   /*
   */
	if (other.name == NULL)
	{
		name = NULL;
	}
	else
	{
		//strcpy(name,other.name);
		char* pnew = new char[strlen(other.name) + 1];
		for (size_t i = 0; i < strlen(other.name); i++)
		{
			pnew[i] = other.name[i];
		}
		pnew[strlen(other.name)] = '\0';
		name = pnew;
	}
}

int main()
{
	Stu stu1(1);
	Stu stu2(stu1);
	stu2.print();
}

举个栗子2:在开辟动态内存时

class Stu
{
	int num;
	int a;
	char* name;
public:
	Stu(int i);
	void print()
	{
		printf("%d\n",num);
		printf("%s\n",name);
	}
	//拷贝
	//Stu(const Stu& other);
    ~Stu(){delete name;}
};
Stu::Stu(int i)
{
	num = i;
	a = 2;
	name = "chi";
}
int main()
{
	Stu stu1(1);
	Stu stu2(stu1);//调用默认的拷贝,为浅拷贝,只是简单的赋值
    //stu2.name == stu1.name 指向同一地方
	return 0;
}

画图;

3调用时机:

1.形参为类的对象的时候,实参和形参结合,形参会调用自己默认的拷贝构造函数

2.函数的返回值类型为类的对象

举个例子:以后再举例子

三、析构函数

1.是什么·?

在类对象生命周期结束的时候,系统自动调用它释放对象

2.定义?~Stu()。,。

函数名为类名 + ~ ,没有返回值类型,

(类比:杯子装水可乐啥的,装东西就是调用构造函数

倒东西就是调用析构函数,不需要知道倒的是什么东西,

所以析构函数没有参数列表,也不能够重构)

3.使用方法:

1.析构函数在一个类中只能够有唯一一个?

不能够重构析构函数

2.调用时机

对象死亡时自动调用(return 0;时还有一种情况是动态释放对象会调用析构函数

3.常见错误:delete释放栈区内存导致错误
#include <stdio.h>
#include <string>

class Stu
{
	int num;
	char* name;
public:
	Stu(char* n);
	~Stu();
	Stu(const Stu& other);//拷贝
};

Stu::Stu(char* n)
{
	if (n != NULL)
	{
		
		name = n;
	}
	else
	name = NULL;
}

Stu::~Stu()
{
	if (name)
		delete[] name;
	name = NULL;
}

Stu::Stu(const Stu& other)
{
	num = other.num;
	if (other.name!=NULL)
	{
		name = new char[strlen(other.name) + 1];
		strcpy(name,other.name);
	}
	else
	name = NULL;
}

int main()
{
	Stu stu1("chj");
	Stu stu2(stu1);
	return 0;

}
4.修改后的代码:
#include <stdio.h>
#include <string>

class Stu
{
	int num;
	char* name;
public:
	Stu(char* n);
	~Stu();
	Stu(const Stu& other);//拷贝
};

Stu::Stu(char* n)
{
	if (!n)
	{
		name = new char[strlen(n) + 1];
		strcpy(name,n);
	}
	else name = NULL;
}

Stu::Stu(const Stu& other)
{
	num = other.num;
	if (other.name)
	{
		name = new char[strlen(other.name) + 1];
		strcpy(name, other.name);
	}
	else
		name = NULL;
}

Stu::~Stu()
{
	if (name)
	{
		delete[] name;
	}
	name = NULL;
}

int main()
{
	Stu stu1("chj");
	Stu stu2(stu1);
	return 0;
}


四、this指针

1.是什么?(指向调用者自身的指针)

1.this指针是系统自动生成的,不是类的成员(不是类的成员),
2.但是每个类的对象都会有自己的this指针,值为对象本身的首地址
3.当类的普通函数在访问类的普通成员的

时候,该this指针总是指向调用者对象

(在普通成员函数访问类数据成员时,隐式的用this指针;这句话是错的)

参考下面的例程:

//自己调试看看num的值有什么问题
#include <stdio.h>

class Stu
{
public:
	int num;
	int a;
public:
	Stu(int num);
};

Stu::Stu(int num)
{
	num = num;
}

int main()
{
	Stu obj(10);
	return 0;
}

2.定义?

没有定义

3.使用:

1.作用域为类内,类外不可使用
2.引出栗子局部变量的屏蔽作用
#include <stdio.h>
#include <string>

class Stu
{
	int num;
public:
	Stu(int num);
};

Stu::Stu(int num)
{
	num = num;//num前面没有this不会自动调用
    //相反这里的num时形参num不是成员num
}


int main()
{
	Stu stu1(10);
	return 0;
}
//修改
Stu::Stu(int num)
{
	this->num = num;
}

3.返回值return this或者是return *this(这里就要用引用去接还是都可以)
#include <stdio.h>
#include <string>

class Stu
{
	int num;
	int a;
public:
	Stu* fun()
	{
		return this;
	}
	Stu(int i);
    Stu& fun2();
};
Stu& Stu::fun2()    
{
    return *this;
}
Stu::Stu(int i)
{
	a = 1;
	num = i;
}

int main()
{
	Stu stu1(10);
	Stu* p = stu1.fun();
	printf("%x %x\n",&stu1,p);
	return 0;
}


LAST:question:类不可以向结构体那样初始化啊(属性为私有)

class Stu
{
    public:
	int num;
	int a;
};
int main()
{
	 Stu stu = {1,2};//error
	return 0;
}

1.public:构造函数只能为共有函数不然会报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值