IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 拷贝构造以及运算符重载 -> 正文阅读

[C++知识库]拷贝构造以及运算符重载

拷贝构造

class Object
{
private:
	int value;
public:
	Object(int x=0) :value(x) //缺省构造函数
	{
		cout << "Create Object:" << this << endl;
	}
	void Print()const
	{
		cout << value << endl;
	}
	~Object() {
		cout << "Object::~Object" << this << endl;
	}
};
int main() 
{
	int n;
	cin >> n;
	Object* s = new Object(n);
	s->Print();
	delete s;

	Object* p = new Object[n]; //必须要有缺省构造函数 才能连续创建一组对象
	//调用malloc函数在堆区申请空间
	//调用构造函数 创建对象
	//返回构建的对象的地址
	for (int i = 0; i < n; ++i)
		(p + i)->Print();


	delete[]p;
	return 0;
}

拷贝构造

在多种情况下会调用拷贝构造
class Object
{
private:
	int value;
public:
	Object(int x=0):value(x)
	{
		
		cout << "Create Object:" << this << endl;
	}
	void Print()const
	{
		cout << value << endl;
	}
	~Object() {
		cout << "Object::~Object " << this << endl;
	}
	void SetValue(int x) { value = x; }
	int GetValue() { return value; }
	Object(const Object& obj) :value(obj.value) 
	//形参为引用 防止死递归
	{
		cout << "Copy Creat " << this << endl;
	}
};
Object fun(Object obj) //3 传参调用拷贝构造 
{
	int val = obj.GetValue();
	Object obja(val); //4 构造对象
	return obja;      //5 返回对象时 调用拷贝构造 构造临时对象
}
int main() {
	Object objx(0); //1 构造对象
	Object objy(0); //2 构造对象
	objy = fun(objx);
	return 0;

}
//构造了5个对象
构造析构对象过程

请添加图片描述

改造上面的代码 减少构建对象的次数
class Object
{
private:
	int value;
public:
	Object(int x=0):value(x)
	{
		
		cout << "Create Object:" << this << endl;
		cout << endl;
	}
	void Print()const
	{
		cout << value << endl;
	}
	~Object() {
		cout << "Object::~Object " << this << endl;
		cout << endl;
	}
	int& Value() //普通方法
	{ 
		return value; 
	}
	const int& Value()const  //常方法
	{ 
		return value; 
	}

	Object(const Object& obj) :value(obj.value) 
	//形参为引用 防止死递归
	{
		cout << "Copy Creat " << this << endl;
		cout << endl;
	}
};
Object fun(const Object &obj) //形参为引用 减少一次对象的构造
{
	//形参前加上const 与此函数功能有关 此函数并不需要改变实参的值
	int val = obj.Value(); //常对象调用常方法 const int& Value()const
	Object obja(val); //3 构造对象
	return obja;      //4 返回时调用拷贝构造构造临时对象
}
int main() {

	Object objx(0); //1 构造对象
	Object objy(0); //2 构造对象
	objy = fun(objx);
	return 0;

}
深拷贝与浅拷贝
#define SEQ_INIT_SIZE 10
#define SEQ_INC_SIZE 2
class SeqList
{
	int* data;
	int maxsize;
	int cursize;
public:
	//构造函数
	SeqList() :data(NULL), maxsize(SEQ_INIT_SIZE), cursize(0)
	{
		data = (int*)malloc(sizeof(int) * maxsize);
	}
	~SeqList()
	{
		free(data);
		data = NULL;
	}

	//系统自动生成的缺省拷贝构造  浅拷贝 
	// 这样会导致 this->data与seq.data指向同一块空间 
	// 主函数结束 调用拷贝构造时 每个对象都要调用拷贝构造 释放资源
	// 将会导致 seq.data同一块内存空间连续释放两次 出现错误
	// 
	//SeqList(const SeqList& seq) :data(seq.data), maxsize(seq.maxsize), cursize(seq.cursize);
	
	//深拷贝
	SeqList(const SeqList& seq):maxsize(seq.maxsize),cursize(seq.cursize)
	{
		data = (int*)malloc(sizeof(int) * maxsize);
		memcpy(data, seq.data, sizeof(data));
	}

	//浅赋值
	/*SeqList& operator=(const SeqList& seq)
	{
		if (this != &seq)
		{		
			maxsize = seq.maxsize;
			cursize = seq.cursize;
			data = seq.data;

			//this->data 将会指向 seq.data 在堆区申请的空间
			//在主函数结束 *this与seq分别调用拷贝构造时
			//将会重复释放 seq.data指向的 堆区空间 产生错误
			//而且 由于*this之前自己在堆区申请的空间 没有释放
			//还会产生内存泄漏
		}
		return *this;
	}*/

	//深赋值
	SeqList& operator=(const SeqList& seq)
	{
		if (this != &seq) 
		{
			free(data);
			maxsize = seq.maxsize;
			cursize = seq.cursize;
			data = (int*)malloc(sizeof(int) * maxsize);
			memcpy(data, seq.data, sizeof(data));
		}
		return *this;
	}
};

实现一个加法函数 尽量少构建对象

	class Complex
{
private:
	double Real, Image;
public:
	Complex() :Real(0), Image(0) {}
	Complex(double r, double i) :Real(r), Image(i) {}
	~Complex() {}
	Complex Add(const Complex& src)const {
		double real = Real + src.Real;
		double image = Image + src.Image;
        
		//Complex tmp(real,image);
		//return tmp;
        //优化为下面一行代码  会减少一次对象的构建
        //优化为只构建 临时对象 不会构建tmp对象
        
		return Complex(real, image);//类型名+()调动构造函数 构造无名对象
	}
	void Print()const
	{
		cout << "Real=" << Real << endl;
		cout << "Image=" << Image << endl;
	}

};
int main() 
{
	Complex c1(1.2, 2.3);
	Complex c2(4.5, 5.6);
	Complex c3;

	c3 = c1.Add(c2);
	c3.Print();
}
1.以对象的引用返回不安全 不允许
	
//返回值为引用 而不是对象
Complex& Add(const Complex& src)const {
		double real = Real + src.Real;
		double image = Image + src.Image;
		//Complex tmp(real,image);
		//return tmp;
		return Complex(real, image);
    //返回值为对象引用 意味着返回将亡值地址
    //此处 将亡值对象 建立在Add 函数空间中
    //那么函数结束 函数空间会被系统回收
    //构建的将亡值对象也会被销毁 
    //此处以引用返回 返回的是构建的将亡值对象的地址
    //一旦函数结束,空间被回收,那么不能以引用返回,这样会有可能在外部访问,已被回收的空间,不允许不安全的。
	}

int main() 
{
	Complex c1(1.2, 2.3);
	Complex c2(4.5, 5.6);
	Complex c3;

	c3 = c1.Add(c2);
	c3.Print();
}
2.以对象返回
//以对象返回	
Complex Add(const Complex& src)const {
		double real = Real + src.Real;
		double image = Image + src.Image;
		//Complex tmp(real,image);
		//return tmp;
		return Complex(real, image);
        //会先构建一个将亡值对象 在主函数空间中构建
        //函数结束 构建的将亡值对象 不会立即被销毁 会保留在调用此函数的那一句代码之后 被销毁
        //消除了以引用返回的不安全 
	}
	void Print()const
	{
		cout << "Real=" << Real << endl;
		cout << "Image=" << Image << endl;
	}

};
int main() 
{
	Complex c1(1.2, 2.3);
	Complex c2(4.5, 5.6);
	Complex c3;

	c3 = c1.Add(c2);
	c3.Print();
}
+运算符的重载
	Complex operator+(const Complex& c)const {
		double real = Real + c.Real;
		double image = Image + c.Image;
		return Complex(real, image);	
	}
	void Print()const
	{
		cout << "Real=" << Real << endl;
		cout << "Image=" << Image << endl;
	}

};
int main() 
{
	Complex c1(1.2, 2.3);
	Complex c2(4.5, 5.6);
	Complex c3;

	c3 = c1 + c2;//调用+运算符重载
	//c3 = c1.operator+(c2);
	//c3 = operator+(&c1, c2);
}

对于设计的任何一个类型 系统都会添加的6种缺省函数

class Object
{
	//C++ 系统添加6个缺省函数
public:
	Object() {}
	~Object() {}
	Object(const Object& x) {}
	Object& operator=(const Object& x) 
	{
		return *this;
	}
    //取 地址符 重载
	Object* operator&() { return this; }//普通对象
	const Object* operator&()const { return this; }//常对象

}

=运算符重载

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x){cout << "Create Object:" << this << endl;}
	~Object() { cout << "Object::~Object " << this << endl; }
	Object(const Object& obj) :value(obj.value)
		//形参为引用 防止死递归
	{
		cout << "Copy Creat " << this << endl;
	}
	/*
	void operator=(const Object& obj) //返回值为void无法做到连续赋值
	{
	//obja=objb=objc;
	// obja=objb.operator=(objc)
	// obja=operator=(&objb,objc); 返回void无法在次赋值 obja

		this->value = obj.value;
	}
	*/
	Object& operator=(const Object& obj) {
		if (this != &obj) { //防止自赋值
			this->value = value;
		}
		return *this;
	}
	//obja=objb=objc;
	// obja=objb.operator=(objc)
	// obja=operator=(&objb,objc);
	//obja.operator=(operator=(&objb,objc));
	//operator=(&obja,operator(&objb,objc));
	int& Value() //普通方法
	{
		return value;
	}
	const int& Value()const  //常方法
	{
		return value;
	}
};

运算符重载

类和成员方法
class Int
{
private:
	int value;
public:
	Int(int x = 0) :value(x)
	{
		cout << "Creat Int: " << this << endl;
	}
	Int(const Int& it) :value(it.value)
	{
		cout << "Copy Creat Int:" << this << endl;
	}
	Int& operator=(const Int& it)
	{
		if (this != &it)//防止自赋值
		{
			value = it.value;
		}
		return *this;
	}
	~Int() 
	{
		cout << "Destroy Int:" << this << endl;
	}
	void Print()const
	{
		cout << value << endl;
	}
};
&重载
	Int* operator&() //普通对象取地址
	{ 
        return this;
    }
---------------------------------------------------------
	const Int* operator&()const //常对象取地址
	{ 
        return this; 
    }
前置++和后置++重载
    Int& operator++() //前置++
	{
		++value;
		return *this;
	}
    //c=++a; 
    //c=a.operator++();  
    //c=operator++(&a);
---------------------------------------------------------
	Int operator++(int) //后置++
	{
		Int old = *this;		
		++* this; // *this<==>a;++*this  ++对象 调动 前置++
		return old;
	}
	//c = a++; //后置++
	//c = a.operator++(0);
	//c = operator++(&a,0);
前置–和后置–重载
	//--重载
	Int& operator--() {
		this->value--;
		return *this;
	}

	Int operator--(int)
	{
		Int old = *this;
		--* this;  //--对象 调用 --重载函数
		return old;
	}

+重载
	//+重载  对象+对象
	Int operator+(const Int& it)const  //对象+对象
	{
		return Int(this->value + it.value);
	}
	//c = a + b; //对象+对象
    //c=a.operator+(b);
    //c=operator+(&a,b);
	c = a + 10;//对象+int
	c = 10 + a;//int+对象
---------------------------------------------------------
    //对象+内置类型 
	Int operator+(const int x)const //对象+内置类型        
	{
		return Int(this->value + x);
	}
    //a=a+10;
    //a=a.operator+(10);
    //a=operator+(&a,10);
---------------------------------------------------------
//内置类型+对象
//由于成员方法 一直都有 this指针
//所以要实现 内置类型+对象  需要消除this指针 位于函数形参列表第一个的问题
//所以要使用全局函数  全局函数并不属于某个类 它的形参列表并不会有this指针
    
Int operator+(const int x, const Int& it) //内置类型+对象
{
	return it + x;//对象+int 调用上面已有函数
}
==与!=重载
    
	bool operator==(const Int& it)const//对象 == 对象
	{
		return this->value == it.value;
	}
---------------------------------------------------------
    
	bool operator!=(const Int& it)const
	{
		return !(*this == it);//调用 == 函数
	}
< ,>=, >, <=重载
	//< >= 重载
	bool operator<(const Int& it)const//对象 < 对象
	{
		return this->value < it.value;
	}
---------------------------------------------------------
	bool operator>=(const Int& it)const
	{
		return !(*this < it);//对象<对象 调用 < 函数
	}
---------------------------------------------------------
	
    //> <= 重载
	bool operator>(const Int& it)const
	{
		return this->value > it.value;
	}
---------------------------------------------------------
	bool operator<=(const Int& it)const
	{
		return !(*this > it); //调用 > 函数
	}
例子
int main()
{
	int i = 0;
	i = i++ + 1; //old版本 2; new 版本 1
	cout << i << endl;
    
	Int a = 0;
	a = a++ + 1;
    
	//a=a.operator++(0) + 1;
	//a = operator++(&a, 0).operator+(1);
	//a = operator+(&operator(&a, 0), 1);
	//a.operator=(operator+(&operator(&a, 0), 1));
	//operator=(&a, operator+(&operator(&a, 0), 1));
    
    //a.value=old.value+1;   a.value=0+1; a.value=1  
    
	a.Print();


}
补充:构造函数具有类型转换功能 内置类型强转为对象

构造函数具有此功能的前提是:构造函数只有单个参数 或者(有多个参数 但是除一个参数无默认值 其它参数都有默认值)

int main()
{
    Int a(10);
    int b=100;
    
    a=b;//隐式转换   b强转为 Int类型的对象
    //构造一个临时对象 值为 b
    //赋值结束析构临时对象
    
}
---------------------------------------------------------
   //构造函数 前加上 关键字 explicit  不允许进行隐式转换
    explicit Int(int x = 0) :value(x)
	{
		cout << "Creat Int: " << this << endl;
	}

int main()
{
    Int a(10);
    int b=100;
    
    //a=b;//error 构造函数加上了关键字 explicit 不允许进行隐式转换
    a=(Int)b;
    //构造一个临时对象 值为 b
    //赋值结束析构临时对象
}
---------------------------------------------------------
 Int(int x,int y=0):value(x+y)
{
    cout<<"Create Int: "<<this<<endl;
}

//Int a(1,2);
//int b=100;
// a = b;  true 虽然构造函数形参列表中,参数个数为2不为1,但是有一个参数有默认值,就相当于只有一个形参
//a=b,20; 逗号表达式值为最右边表达式的值  =>20 

//a=(Int)(b,20)  =>  a=(Int)(20)
//通过强转产生一个临时对象 必须要求构造函数具有单个参数

//a=Int(b,20) 产生一个无名的临时对象 传递两个参数为 b,20 
强转运算符重载 对象强转为内置类型
//强转运算符重载  对象强转为内置类型
	operator int()const
	{  
		return value;
	}

// Int a(10);
//int b = 100;
//a = (Int)b;

//b=a; 内置类型=对象
//b=a.operator int();
//b=operator int(&a);
//b=(int)a;
//b=a.value;
完整代码
class Int
{
private:
	int value;
public:
	explicit Int(int x = 0) :value(x)
	{
		cout << "Creat Int: " << this << endl;
	}
	Int(const Int& it) :value(it.value)
	{
		cout << "Copy Creat Int:" << this << endl;
	}
	Int& operator=(const Int& it)
	{
		if (this != &it)//防止自赋值
		{
			value = it.value;
		}
		cout << this << "=" << &it << endl;
		return *this;
	}
	~Int() 
	{
		cout << "Destroy Int:" << this << endl;
	}
	void Print()const
	{
		cout << value << endl;
	}
	Int* operator&() //普通对象取地址
	{ return this; }
	const Int* operator&()const //常对象取地址
	{ return this; }
    //++重载
	Int& operator++() //前置++
	{
		++value;
		return *this;
	}//c=++a; c=a.operator++();  c=operator++(&a);
	Int operator++(int) //后置++
	{
		Int old = *this;		
		++* this; // *this==a  ++*this 调动 前置++
		return old;
	}
	//--重载
	Int& operator--() {
		this->value--;
		return *this;
	}
	Int operator--(int)
	{
		Int old = *this;
		--* this;  //--对象 调用 --重载函数
		return old;
	}

	//+重载
	Int operator+(const Int& it)const //对象+对象
	{
		return Int(this->value + it.value);
	}
	Int operator+(const int x)const//对象+内置类型
	{
		return Int(this->value + x);
	}

	//== != 重载
	bool operator==(const Int& it)const//对象 == 对象
	{
		return this->value == it.value;
	}
	bool operator!=(const Int& it)const
	{
		return !(*this == it);//调用 == 函数
	}
	
	//< >= 重载
	bool operator<(const Int& it)const//对象 < 对象
	{
		return this->value < it.value;
	}
	bool operator>=(const Int& it)const
	{
		return !(*this < it);//调用 < 函数
	}

	//> <= 重载
	bool operator>(const Int& it)const
	{
		return this->value > it.value;
	
	}
	bool operator<=(const Int& it)const
	{
		return !(*this > it); //调用 > 函数
	}
	//强转运算符重载  对象强转为内置类型
	operator int()const
	{  
		return value;
	}

};
Int operator+(const int x, const Int& it) //内置类型+对象
{
	return it + x;//对象+int 调用上面已有函数
}
()运算符重载
class Add
{
private:
	//在成员属性上 加上 mutable 关键字
	//在常方法中依然可以修改 对应的成员属性的值
	mutable int value;
public:
	Add(int x = 0) :value(x) {}

	//()运算符重载
	int operator()(int a, int b)const
	{
		//在成员属性前加上了 mutable 关键字
		//在常方法中依然可以修改 对应的成员属性的值
		value = a + b;
		return value;
	}
};
int main()
{
	int a = 10, b = 20, c = 0;
	Add add;

	c = add(a, b);//重载()运算符 称作 仿函数
	//add(a,b); 有可能是函数名 也有可能是对象
	//重载了()运算符之后 此处就是对象
	
	//c = add.operator()(a, b);

	c = Add()(a, b);
	//Add()调用构造函数 返回一个将亡值对象
	//对象(a,b) 调用()运算符重载
	//返回重载函数的返回值 c=a+b;

	return 0;
}
*与->重载
class Int
{
private:
	int value;
public:
	Int(int x=0) :value(x)
	{
		cout << "Creat Int: " << this << endl;
	}
	Int(const Int& it) :value(it.value)
	{
		cout << "Copy Creat Int:" << this << endl;
	}
	Int& operator=(const Int& it)
	{
		if (this != &it)//防止自赋值
		{
			value = it.value;
		}
		cout << this << "=" << &it << endl;
		return *this;
	}
	~Int()
	{
		cout << "Destroy Int:" << this << endl;
	}
	int& Value() { return value; }
	const int& Value()const { return value; }
};
class Object
{
	Int* ip;
public:
	Object(Int* s = NULL) :ip(s) {}
	~Object()
	{
		if (ip != NULL)
		{
			delete ip;
		}
		ip = NULL;
	}
	//*运算符重载
	Int& operator*()
	{
		return *ip;
	}
	const Int& operator*()const
	{
		return *ip;
	}

	//->运算符重载
	Int* operator->() 
	{
		return &**this;
		//*this => 对象 
		//**this=>*(*this)=>*(对象) 调用*重载函数
		//*重载函数返回对象本身
		// &*(*this) => &对象 就是对象的地址
		//return ip;
	}
	const Int* operator->()const
	{
		return &**this;
		//return ip;
	}
	
};
int main()
{
	Object obj(new Int(10));
	//主函数结束 析构函数会自动释放在堆区申请的空间

	Int* p = new Int(1);
	//需要自己手动释放在堆区申请的空间

	(*p).Value();

	(*obj).Value();
	//调用*运算符重载 返回Int 对象
	//然后调用 Int 对象的成员方法

	p->Value();

	obj->Value();

	delete p;
}
类String << + 运算符重载
class String
{
	char* str;
	String(char* p, int)
	{
		str = p; 
		//对象死亡调用析构函数时 就会释放p之前指向的空间
		//防止了内存泄漏
	}
public:
	String(const char* p = NULL) :str(NULL)
	{
		if (p != NULL)
		{
			str = new char[strlen(p) + 1];
			strcpy_s(str, strlen(p) + 1,p);
		}
		else 
		{
			str = new char[1];
			*str = '\0';
		}	
	}
	~String()
	{
		if (str != NULL)
		{
			delete[]str;
		}
		str = NULL;
	}
	//ostream& operator<<(const String* const this, ostream& out);
    //输出流运算符重载
    //s<<out;
    //s.operator<<(out);
    //operator<<(&s,out);
	ostream& operator<<(ostream& out)const
	{
		if (str != NULL) 
		{
			out << str;
		}
		return out;
	}

	//s1<<cout;
	//s1.operator(cout);
	//operator(&s1,cout);
	String(const String& src):str(NULL)
	{
		str = new char[strlen(src.str) + 1];
		strcpy_s(str, strlen(src.str) + 1, src.str);
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			delete[]str;
			str = new char[strlen(s.str) + 1];
			strcpy_s(str, strlen(s.str) + 1, s.str);
		}
		return *this;
	}
    
	//对象+对象
	String operator+(const String& s)const
	{
		/*
		
		String tmp;
		delete[]tmp.str;
		tmp.str = new char[strlen(this->str) + strlen(s.str) + 1];
		strcpy_s(tmp.str, strlen(str)+1, str);
		//strcpy_s(sa.str + strlen(str), strlen(s.str) + 1, s.str);
		strcat_s(tmp.str,strlen(tmp.str)+strlen(s.str)+1,s.str);	
		return tmp;*/

		char* p = new char[strlen(this->str) + strlen(s.str) + 1];
		//p指向的 内存可能没有释放  上面重新设计了一个私有构造函数 解决此问题
		strcpy_s(p, strlen(str) + 1, str);
		strcat_s(p, strlen(p) + strlen(s.str) + 1, s.str); //中间的参数 为前后两个 前后两个字符串长度+1;
		return String(p,1);
	}
	//对象+字符串
	String operator+(const char* s)const
	{		
		char* p = new char[strlen(this->str) + strlen(s) + 1];
		//p指向的 内存可能没有释放  上面重新设计了一个私有构造函数 解决此问题
		strcpy_s(p, strlen(str) + 1, str);
		strcat_s(p, strlen(p) + strlen(s) + 1, s); //中间的参数 为前后两个 前后两个字符串长度+1;
		return String(p, 1);//调动了自己写的特殊的 构造函数
		//return *this + String(s);
	}	
};
//字符串+对象
String operator+(const char* s, const String& src)
{
	//对象+对象 调用已有的函数
	return String(s) + src;
}
//实现  ostream类型对象 <<String对象  =》 cout<<s1
//实现格式化 coout<<String对象<<endl;
ostream&  operator<<(ostream& out, const String& s)
{
    //调用已有的类内方法
	s << out;
	return out;
	//s.operator<<(out);
	//operator<<(&s, out);
}
int main() 
{
	String s1("yhping");
	//cout << s1<<endl;
	//operator<<(cout, s1);
	String s2("hello");
	String s3;
	s3 = s1 + s2;
	
	s3 = s1 + "newdata";
	
	s3 = "newdata" + s1;
	cout << s3 << endl;
}

如何使得堆内空间多次利用 而不产生不良影响

左值右值的的定义
//lvalue 左值   xvalue   rvalue 右值   prvalue 重右值
//左值可以取地址&;  生存期和变量名一样 
//右值 不可以取地址 因为无名字
//字面常量 比如:10 叫做重右值
int main() {
	//可以取地址的值就是左值
	int a = 10;  //左值
	//左值可以取地址&a;  生存期和变量名一样 
    //右值 不可以取地址 无名字
    
	int& b = a;
    int&& c=10;
    //int&& d = c; error c虽然是10的右值引用 但是 此处c是个变量名已经具有名字  一旦具有名字就不是右值 就变成一个左值了  
	//具有名字 就是左值
    
    String s1;
    String& sx=s1; //正确
    //String& sx=String("hello");// error 调用构造函数构造的是一个无名对象 不具有名字;  左值引用必须引用一个具有名字的对象
    String&& sy=String("hello");// true 调用构造函数构造的是一个无名对象  可以使用右值引用 

}
使用 移动拷贝构造函数 和移动赋值函数
   
   //移动拷贝构造  移动的是资源
  //移动构造就是用于建立将亡值对象的构造函数
   //可以使一块资源只创建一次 得到充分的利用
   // 构造无名对象调用 移动构造函数
//函数返回值为对象时 返回时会调用 拷贝构造 构造无名对象也就是将亡值对象 也会调用 移动构造函数
    String(String&& s)
	{
		cout << "move copy constructor" << this << endl;
		str = s.str;//实现资源的移动 此处的资源是堆区申请的空间 
        //转移堆区资源
		s.str = NULL;
	}

    //移动赋值函数
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			str = s.str;//实现资源的移动  此处的资源是堆区申请的空间 
			s.str = NULL;
		}
		cout << "move operator=: " << &s << endl;
		return *this;
	}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qa6BJtMF-1650035516请添加图片描述
142)(image-20220125124203755.png)]

类String完整代码
class String
{
	char* str;
	String(char* p, int)
	{
		str = p; 
		//对象死亡调用析构函数时 就会释放p之前指向的空间
		//防止了内存泄漏
	}
public:
	String(const char* p = NULL) :str(NULL)
	{
		if (p != NULL)
		{
			str = new char[strlen(p) + 1];
			strcpy_s(str, strlen(p) + 1,p);
		}
		else 
		{
			str = new char[1];
			*str = '\0';
		}	
	}
	~String()
	{
		if (str != NULL)
		{
			delete[]str;
		}
		str = NULL;
	}
	//ostream& operator<<(const String* const this, ostream& out);
	ostream& operator<<(ostream& out)const
	{
		if (str != NULL) 
		{
			out << str;
		}
		return out;
	}

	//s1<<cout;
	//s1.operator(cout);
	//operator(&s1,cout);
	String(const String& src):str(NULL)
	{
		str = new char[strlen(src.str) + 1];
		strcpy_s(str, strlen(src.str) + 1, src.str);
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			delete[]str;
			str = new char[strlen(s.str) + 1];
			strcpy_s(str, strlen(s.str) + 1, s.str);
		}
		return *this;
	}
	//对象+对象
	String operator+(const String& s)const
	{
		/*
		
		String tmp;
		delete[]tmp.str;
		tmp.str = new char[strlen(this->str) + strlen(s.str) + 1];
		strcpy_s(tmp.str, strlen(str)+1, str);
		//strcpy_s(sa.str + strlen(str), strlen(s.str) + 1, s.str);
		strcat_s(tmp.str,strlen(tmp.str)+strlen(s.str)+1,s.str);	
		return tmp;*/

		char* p = new char[strlen(this->str) + strlen(s.str) + 1];
		//p指向的 内存可能没有释放  上面重新设计了一个私有构造函数 解决此问题
		strcpy_s(p, strlen(str) + 1, str);
		strcat_s(p, strlen(p) + strlen(s.str) + 1, s.str); //中间的参数 为前后两个 前后两个字符串长度+1;
		return String(p,1);
	}
	//对象+字符串
	String operator+(const char* s)const
	{		
		char* p = new char[strlen(this->str) + strlen(s) + 1];
		//p指向的 内存可能没有释放  上面重新设计了一个私有构造函数 解决此问题
		strcpy_s(p, strlen(str) + 1, str);
		strcat_s(p, strlen(p) + strlen(s) + 1, s); //中间的参数 为前后两个 前后两个字符串长度+1;
		return String(p, 1);//调动了自己写的特殊的 构造函数
		//return *this + String(s);
	}	
	String(String&& s)
	{
		cout << "move copy constructor" << this << endl;
		str = s.str;
		s.str = NULL;
	}
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			delete[]str;
			str = s.str;
			s.str = NULL;
		}
		cout << "move operator=: " << &s << endl;
		return *this;
	}
};
//字符串+对象
String operator+(const char* s, const String& src)
{
	//对象+对象 调用已有的函数
	return String(s) + src;
}
//实现  ostream类型对象 <<String对象  =》 cout<<s1
ostream&  operator<<(ostream& out, const String& s)
{
	s << out;
	return out;
	//s.operator<<(out);
	//operator<<(&s, out);
}
String fun()
{
	String s2("yhping");
	return s2;  //不具名对象
}
int main()
{
	String s1;
	s1 = fun();
	cout << s1 << endl;
}

类成员中有其它类对象 它们之间构造和析构的调用顺序

对象中成员的构建顺序和声明的顺序保持一致,与参数列表无关

1.在函数体中对类的成员进行赋值
class Int
{
private:
	int value;
public:
	Int(int x=0) :value(x)
	{
		cout << "Creat Int: " << this << endl;
	}
	Int(const Int& it) :value(it.value)
	{
		cout << "Copy Creat Int:" << this << endl;
	}
	Int& operator=(const Int& it)
	{
		if (this != &it)//防止自赋值
		{
			value = it.value;
		}
		cout << this << "=" << &it << endl;
		return *this;
	}
	~Int()
	{
		cout << "Destroy Int:" << this << endl;
	}
};
class Object
{
private:
	int num;
	Int val;
public:
	Object(int x, int y)
	{
		cout << "Creat Object: " << this << endl;
		num = x;
		val = y; //对象=int 进行隐式的强转 构建临时对象 临时对象的值为 y
	}
	~Object()
	{
		cout << "Destroy Object: " << this << endl;
	}
};
int main()
{
	Object obj(1, 2);
    
    //对象的构建顺序
    //在调用构造函数之前 系统会为要构造的对象 分配了空间
    //在进入构造函数之前 先构建 成员属性 构建num 构建Int对象 val
    //进入构造函数的函数体
    //析构先析构 本类对象
    //在析构成员属性 中的对象 Int
}
运行结果

请添加图片描述

2.在初始化列表中对类的成员进行赋值
	Object(int x, int y):num(x),val(y)
	{
		cout << "Creat Object: " << this << endl;
        //num=x;
        //val=y; //对象=int 进行隐式的强转 构建临时对象 临时对象的值为 y

	}
//在初始化列表中进行赋值   或者在函数体中进行赋值
//对于内置类型效果是一样的
//对于自己设计的类型来说  这样会减少一次 临时对象的构建和析构

运行结果

请添加图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:22:53  更:2022-04-18 17:25:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:22:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码