C++ 面向对象之构造函数

C++ 面向对象之构造函数,第1张

C++的构造函数是用来对对象初始化 *** 作,下面将对几种构造函数使用上进行详细说明。

默认构造函数

创建对象的时候且不传递任何参数的时候自动调用

合成默认构造函数(编译器自动创建)

创建对象的时候不传递任何参数,用户在程序没有定义默认函数,那么由编译器自动创建。
1)类成员数据没有类内初始值,使用默认初始化实际不做任何 *** 作。

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();
	int getClassNum();
	void setAddr();

private:  // 保护类内属性
	string className;
	char* addr;
	int classNum;
};

// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr() {

}


int main() {
	Cls c1;  // 此时调用合成默认参数构造函数
	cout << c1.getClassNum() << endl;

	system("pause");
	return 0;
}

输入、输出:

0

结论:没有任何意义的默认构造函数

2)当类内数据有初始化的值时,编译器创建的合成默认构造使用这个值对创建的对象初始化。
类内初始值在C++11及以上的标准才支持

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();
	int getClassNum();
	void setAddr();

private:  // 保护类内属性
	// 类内数据有初始值
	string className = "大班";  
	char* addr = NULL;
	int classNum = 12;
};

// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr() {

}


int main() {
	Cls c1;  // 此时调用合成默认参数构造函数,并且把类内初始化值拿来给对象初始化
	cout << c1.getClassNum() << endl;
	cout << c1.getClassName() << endl;

	system("pause");
	return 0;
}

输入、输出:

12
大班

结论:当类内数据全部都使用了初始值,然后使用合成默认构造函数才有意义

用户定义默认构造函数

手动定义的默认构造函数是最好的,因为规范化的时候类内初始是不存在的。所以我们创建对象的时候一般通过默认构造函数来进行数据初始化。

代码:

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();
	int getClassNum();
	void setAddr();
	// 自定义默认构造函数:没有返回值和类名相同
	Cls();  
private:  // 保护类内属性
	
	string className;
	char* addr;
	
	// 当自定义默认构造函数也修改了改数据,那么该类内初始值既被覆盖
	int classNum = 12;
};

// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr() {

}

// 使用自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";
	addr = NULL;
	classNum = 13;
}


int main() {
	Cls c1;  // 此时调用自定义默认参数构造函数,然后对对象初始
	cout << c1.getClassNum() << endl;  // 用户自定义初始化值。覆盖了类内初始值。
	cout << c1.getClassName() << endl;

	cout << "**************" << endl;

	Cls c2;  // 此时调用自定义默认参数构造函数,然后对对象初始
	cout << c2.getClassNum() << endl;
	cout << c2.getClassName() << endl;

	system("pause");
	return 0;
}

输入、输出:

自定义默认构造函数被调用
13
小班
**************
自定义默认构造函数被调用
13

结论:当某个数据成员在类内初始化后,同时也在构造函数中进行了初始化 *** 作,那么以构造函数中的为准。
相当于构造函数中的初始化,会覆盖类内初始化。

自定义带参数的构造函数

创建对象的传递参数,调用该构造函数。
自定义带参数的构造函数可以发生重载。

代码:

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();
	int getClassNum();
	char* getAddr();
	void setAddr();
	void descrirition();

	Cls();  // 自定义默认构造函数:没有返回值和类名相同
	Cls(int classNum, string className, const char* addr);  // 自定义参数构造函数
	Cls(int classNum, string className);  // 自定义参数构造函数重载

private:  // 保护类内属性

	string className;
	char* addr = NULL;
	int classNum;
};


// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

char* Cls::getAddr() {
	return addr;
}
void  Cls::setAddr() {

}

// 自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";
	addr = NULL;
	classNum = 11;
}

void Cls::descrirition() {
	cout << "addr: " << addr 
		<< " className:" << className 
		<< "classNum:" << classNum << endl;

}


// 自定义参数构造函数
Cls::Cls(int classNum, string className,const char* addr) {
	cout << "自定义参数构造函数-重载1" << endl;

	this->classNum = classNum;
	this->className = className;
	this->addr = (char*)addr;
}

// 自定义参数构造函数重载
Cls::Cls(int classNum, string className) {
	cout << "自定义参数构造函数-重载2" << endl;

	this->classNum = classNum;
	this->className = className;
}

int main() {
	Cls c1(13, "大班");
	cout << " className:" << c1.getClassName()
	<< " classNum:" << c1.getClassNum() << endl;

	Cls c2(12, "中班", "北京");
	c2.descrirition();

	system("pause");
	return 0;
}

输入、输出:

自定义参数构造函数-重载2
 className:大班 classNum:13
自定义参数构造函数-重载1
addr: 北京 className:中班classNum:12

结论:
1、自定义带参数构造函数用于创建对象带参数
2、自定义带参数构造函数可以发生重载

拷贝构造函数

拷贝函数在什么时候被调用?

拷贝构造函数也有合成拷贝构造函数(编译器自动创建)和自定义拷贝构造函数之分。
合成拷贝构造函数是浅拷贝,而我们自定义的一般使用深拷贝。
深浅拷贝一般针对的是指针,在堆区开辟内存空间,后面程序中我们会细讲。

合成拷贝构造函数

合成拷贝构造函数编译器自动创建,浅拷贝。

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();
	int getClassNum();
	char* getAddr();
	void setAddr(const char* addr);
	void descrirition();

	Cls();  // 自定义默认构造函数:没有返回值和类名相同
	Cls(int classNum, string className, const char* addr);  // 自定义参数构造函数
	Cls(int classNum, string className);  // 自定义参数构造函数重载

private:  // 保护类内属性

	string className;
	char* addr = NULL;
	int classNum;
};


// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

char* Cls::getAddr() {
	return addr;
}
void  Cls::setAddr(const char* addr) {
	strcpy_s(this->addr, 20, addr);
}

// 自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";

	addr = NULL;
	classNum = 11;
}

void Cls::descrirition() {
	cout << "addr: " << addr 
		<< " className:" << className 
		<< "classNum:" << classNum << endl;

}

// 自定义参数构造函数
Cls::Cls(int classNum, string className,const char* addr) {
	cout << "自定义参数构造函数-重载1" << endl;

	this->classNum = classNum;
	this->className = className;
	this->addr = new char[20];
	strcpy_s(this->addr, 20, addr);
}

// 自定义参数构造函数重载
Cls::Cls(int classNum, string className) {
	cout << "自定义参数构造函数-重载2" << endl;

	this->classNum = classNum;
	this->className = className;
}


int main() {
	Cls c1(12, "中班", "北京");
	
	// 使用已创建的对象来创建对象调用,拷贝构造函数
	Cls c2 = c1;  // 这里针对指针数据只是复制了地址
	Cls c3(c1);

	c1.descrirition();
	c2.descrirition();
	
	cout << "修改" << endl;

	c1.setAddr("南京");
	c1.descrirition();
	c2.descrirition();

	system("pause");
	return 0;
}

输入、输出:

自定义参数构造函数-重载1
addr: 北京 className:中班classNum:12
addr: 北京 className:中班classNum:12
修改
addr: 南京 className:中班classNum:12
addr: 南京 className:中班classNum:12

结论:
1、编译器自动生成的合成拷贝构造函数是浅拷贝

自定义拷贝构造函数

代码:

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();  // 获取classname
	int getClassNum();     // 获取classNum  
	void setAddr(const char* addr);   // 修改addr  
	void descrirition();  // 打印对象描述信息

	Cls(const Cls& other);  // 深浅拷贝
	Cls();  // 自定义默认构造函数:没有返回值和类名相同
	Cls(int classNum, string className, const char* addr);  // 自定义参数构造函数
	Cls(int classNum, string className);  // 自定义参数构造函数重载

private:  // 保护类内属性
	string className;
	char* addr = NULL;
	int classNum;
};


// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr(const char* addr) {
	strcpy_s(this->addr, 20, addr);
}

// 自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";

	addr = NULL;
	classNum = 11;
}

void Cls::descrirition() {
	cout << "addr: " << addr 
		<< " className:" << className 
		<< "classNum:" << classNum << endl;

}

// 自定义参数构造函数
Cls::Cls(int classNum, string className,const char* addr) {
	cout << "自定义参数构造函数-重载1" << endl;

	this->classNum = classNum;
	this->className = className;
	this->addr = new char[20];
	strcpy_s(this->addr, 20, addr);
}

// 自定义参数构造函数重载
Cls::Cls(int classNum, string className) {
	cout << "自定义参数构造函数-重载2" << endl;

	this->classNum = classNum;
	this->className = className;
}

// 浅拷贝
Cls::Cls(const Cls& other) {
	cout << "浅拷贝" << endl;
	
	className  = other.className;
	classNum = other.classNum 
	addr = other.addr;
}

 深拷贝
//Cls::Cls(const Cls& other) {
//     注意这里一定要在堆区重新开辟空间
//		className  = other.className;
//     classNum = other.classNum 
//     addr = new char[20];
//	  strcpy_s(addr, 20, other.addr);
//}
int main() {
	Cls c1(12, "中班", "北京");
	
	// 使用已创建的对象来创建对象调用,拷贝构造函数
	Cls c2 = c1;
	Cls c3(c1);

	c1.descrirition();
	c2.descrirition();
	
	cout << "修改" << endl;

	c1.setAddr("南京");
	c1.descrirition();
	c2.descrirition();

	system("pause");
	return 0;
}

输入、输出:

自定义参数构造函数-重载1
浅拷贝
浅拷贝
addr: 北京 className:中班classNum:12
addr: 北京 className:classNum:0
修改
addr: 南京 className:中班classNum:12
addr: 南京 className:classNum:0
拷贝构造函数的调用时间

1、利用已有的对象构建新的对象
2、对象作为函数的形参,并且不是引用
3、对象作为函数返回值,并且不是引用
4、对象作为数组成员

代码:

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();  // 获取classname
	int getClassNum();     // 获取classNum  
	void setAddr(const char* addr);   // 修改addr  
	void descrirition();  // 打印对象描述信息

	Cls(const Cls& other);  // 深浅拷贝
	Cls();  // 自定义默认构造函数:没有返回值和类名相同
	Cls(int classNum, string className, const char* addr);  // 自定义参数构造函数
	Cls(int classNum, string className);  // 自定义参数构造函数重载

private:  // 保护类内属性
	string className;
	char* addr = NULL;
	int classNum;
};


// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr(const char* addr) {
	strcpy_s(this->addr, 20, addr);
}

// 自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";

	addr = NULL;
	classNum = 11;
}

void Cls::descrirition() {
	cout << "addr: " << addr 
		<< " className:" << className 
		<< "classNum:" << classNum << endl;

}

// 自定义参数构造函数
Cls::Cls(int classNum, string className,const char* addr) {
	cout << "自定义参数构造函数-重载1" << endl;

	this->classNum = classNum;
	this->className = className;
	this->addr = new char[20];
	strcpy_s(this->addr, 20, addr);
}

// 自定义参数构造函数重载
Cls::Cls(int classNum, string className) {
	cout << "自定义参数构造函数-重载2" << endl;

	this->classNum = classNum;
	this->className = className;
}

// 浅拷贝
//Cls::Cls(const Cls& other) {
//	cout << "浅拷贝" << endl;
//	className  = other.className;
//  classNum = other.classNum;
//	addr = other.addr;
//}

// 深拷贝
Cls::Cls(const Cls& other) {
	  cout << "深拷贝" << endl;

	  className = other.className;
	  classNum = other.classNum;
	  // 注意这里一定要重新在堆区创建空间
	  addr = new char[20];
	  strcpy_s(addr, 20, other.addr);
}

// 对象作为函数参数
void getMeag(Cls c) {
	c.descrirition();
}

// 对象作为函数返回值
Cls clsReturn(Cls& c1, Cls& c2) {
	if (c1.getClassNum() >= c2.getClassNum()) {
		return c1;
	}
	else return c2;
}

int main() {
	Cls c1(12, "中班", "北京");

	// 1、使用已创建的对象来创建对象调用拷贝构造函数
	Cls c2 = c1;
	Cls c3(c1);

	c1.descrirition();
	c2.descrirition();
	
	cout << "修改" << endl;

	c1.setAddr("南京");
	c1.descrirition();
	c2.descrirition();

	// 2、作为函数形参
	getMeag(c1);
	
	// 3、作为函数返回值
	clsReturn(c1, c2);

	//4、作为数组成员
	Cls C3[3] = {c1, c2, c3}; // C3[0]=c1 ....C3[2]=c3

	system("pause");
	return 0;
}

输入、输出:

自定义参数构造函数-重载1
深拷贝
深拷贝
addr: 北京 className:中班classNum:12
addr: 北京 className:中班classNum:12
修改
addr: 南京 className:中班classNum:12
addr: 北京 className:中班classNum:12
深拷贝
addr: 南京 className:中班classNum:12
深拷贝
深拷贝
深拷贝
深拷贝

总结:
1、四种拷贝构造函数被调用时间
2、深浅拷贝
3、对象作为函数返回值和参数的时候,如果不是引用。那么会拷贝一份对象,占用内存空间。

赋值构造函数

对象创建完毕以后出现对象和对象赋值,会调用赋值构造函数

代码:

#include 
#include 
#include 

using namespace std;

// 类声明
class Cls {
public:
	string getClassName();  // 获取classname
	int getClassNum();     // 获取classNum  
	void setAddr(const char* addr);   // 修改addr  
	void descrirition();  // 打印对象描述信息

	Cls(const Cls& other);  // 深浅拷贝
	Cls();  // 自定义默认构造函数:没有返回值和类名相同
	Cls(int classNum, string className, const char* addr);  // 自定义参数构造函数
	Cls(int classNum, string className);  // 自定义参数构造函数重载
	Cls& operator=(const Cls& other);  // 赋值构造函数
private:  // 保护类内属性
	string className;
	char* addr = NULL;
	int classNum;
};


// 类内成员函数定义
string Cls::getClassName() {
	return className;
}

int  Cls::getClassNum() {
	return classNum;
}

void  Cls::setAddr(const char* addr) {
	strcpy_s(this->addr, 20, addr);
}

// 自定义默认构造函数来进行对象初始化
Cls::Cls() {
	cout << "自定义默认构造函数被调用" << endl;

	className = "小班";

	addr = new char[20];
	classNum = 11;
}

void Cls::descrirition() {
	cout << "addr: " << addr 
		<< " className:" << className 
		<< "classNum:" << classNum << endl;

}

// 自定义参数构造函数
Cls::Cls(int classNum, string className,const char* addr) {
	cout << "自定义参数构造函数-重载1" << endl;

	this->classNum = classNum;
	this->className = className;
	this->addr = new char[20];
	strcpy_s(this->addr, 20, addr);
}

// 自定义参数构造函数重载
Cls::Cls(int classNum, string className) {
	cout << "自定义参数构造函数-重载2" << endl;

	this->classNum = classNum;
	this->className = className;
}

// 赋值拷贝构造函数
Cls& Cls::operator=(const Cls& other) {
	cout << "赋值拷贝构造函数" << endl;

	// 防止出现c1 = c1;
	if (this == &other) {
		return *this;
	}

	className = other.className;
	classNum = other.classNum;

	return *this;  // 链式编程 c1 = c2 = c3;
}

int main() {
	Cls c1, c2;
	c2 = c1;


	system("pause");
	return 0;
}

输入、输出:

自定义默认构造函数被调用
自定义默认构造函数被调用
赋值拷贝构造函数

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/867534.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-12
下一篇2022-05-12

发表评论

登录后才能评论

评论列表(0条)

    保存