C++中基类与派生类的复制控制

本文探讨了C++中基类与派生类的复制控制问题,通过实例分析了调用复制构造函数在不同情况下的行为。在调用带有基类对象参数的函数时,错误的复制构造函数可能导致乱码。当形参为引用时,不会产生副本,因此不受复制构造函数影响。此外,派生类可以隐式转换为基类,但基类不能直接转换为派生类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本博文的创作思路源自《C++ Primer(4th Ed )》的习题15.20

运行环境Ubuntu 、g++

#include <iostream>
#include <string>
using namespace std;
class Item_base
{
	public:
		Item_base(const string &book = "Item_base", double SalesPrice = 1):
			isbn(book), price(SalesPrice) 
		{
			cout << "构造函数Item_base(const string&, double )" << endl;
		}
		virtual double NetPrice(size_t n) const	//不同购买量不同计价方式
		{
			return n * price;
		}
		Item_base(const Item_base& it)	//复制构造函数
		{ 
			//isbn = it.isbn;
			//price = it.price;
			cout << " 复制构造函数Item_base(const Item_base& it) " << endl; }
		Item_base& operator =(const Item_base& right)
		{
			isbn = right.isbn;
			price = right.price;
			cout << "赋值函数Item_base::operator =(Item_base& left, Item_base& right)" << endl;
			return *this;// return *left;
		}
		virtual ~Item_base() //
		{ cout << "析构函数~Item_base" << endl; }	
		void print()
		{ cout << "isbn:" <<isbn << "    price:" << price << endl;}
	private:
		string isbn;
	protected:
		double price;
};
//Item_base& Item_base::operator =(Item_base& left, Item_base& right)
//{
	//left.isbn = right.isbn;
	//left.price = right.price;
	//cout << "Item_base::operator =(Item_base& left, Item_base& right)" << endl;
	//return *this;// return *left;
//}

class Bulk_item : public Item_base
{
	public:
		Bulk_item(const string &book ="bulk_item", double SalesPrice = 2,
				size_t qty = 0, double dis = 0.0) :
		Item_base(book, SalesPrice), min_qty(qty), discount(dis)
		{ cout << "构造函数Bulk_item(const string &book, double, size_t, double)" << endl; }
		
		double NetPrice(size_t cnt) const
		{
			if(cnt < min_qty)
				return cnt * price;
			else
				return cnt * (1 - discount) * price;
		}
		Bulk_item(const Bulk_item & Bulk)	
		{	
			
			cout << "复制构造函数Bulk_item(const Bulk_item &)" << endl; }
		Bulk_item& operator=(Bulk_item& right)
		{
			if(this != &right)
				Item_base::operator =(right);
			min_qty = right.min_qty;
			discount = right.discount;
			cout << "赋值函数Bulk_item& oprator=(Bulk_item& right)" << endl;
			return *this;
		}
		virtual ~Bulk_item()	//
		{	cout << "析构函数~Bulk_item()" << endl; }
		
	private:
		size_t min_qty;
		double discount;
};

void func1(Item_base obj)
{
	obj.print();
}
void func2(Item_base& obj)
{
	obj.print();
}
Item_base func3()
{
	Item_base obj;
	return obj;
}

int main()
{
	Item_base item; //调用构造函数,并在最后析构
	cout << "1" << endl<<endl;
	func1(item);	//调用复制构造函数,目的是将形参item_base对象创建为实参item_base对象的副本
				//函数执行完毕后调用item_base的析构函数,撤销形参对象,
	cout << "3" << endl<<endl;
	func2(item);	//不调用复制构造函数传递实参,因为形参为Item_base对像的引用
	cout << "4" << endl<<endl;
	item = func3(); //调用构造函数,创建Item_base对象
					//调用赋值函数
					//在函数接受时调用析构函数撤销刚刚创建的对象
	cout << "5" << endl<<endl;
	Item_base *p = new Item_base; //调用构造函数创建动态Item_base对象
	cout << "6" << endl<<endl;
	delete p; //调用析构函数撤销刚刚动态创建的Item_base对象
	cout << "7" << endl<<endl;
	Bulk_item bulk;	//调用bulk_item构造函数创建bulk_item对象,由于是派生类对象
					//在调用这个构造函数时会先调用item_base构造函数
					//并在最后析构
	cout << "8" << endl<<endl;
	func1(bulk);	//bulk_item会隐式转换为item_base
				//调用item_base的复制构造函数,目的是将形参item_base对象创建为实参item_base对象的副本。
	cout << "9" << endl << endl;
	func2(bulk);  //bulk_item会隐式转换为item_base
	cout << "10" << endl << endl;
	//Item_base item;
	//bulk = func3();	//调用失败,因为item_base不会隐式转换为bulk_item
	//cout << "11" << endl << endl;
	Bulk_item *q = new Bulk_item;  //动态创建,调用的函数与创建Bulk_item对象相同,不再赘述
	cout << "12" << endl << endl;
	delete q;	//调用~bulk_item与~item_base撤销动态创建的对象
	cout << "13" << endl << endl;
}
程序在何时执行哪个函数已在注释行说的很清楚了。这里只是有点要说名:

在调用func1(item)时会出现乱码:

如图:


原因是因为它调用的是合成版本的复制构造函数,如果将item_base复制构造函数里的两个注释行取消掉,将不会出现这种情况

isbn = it.isbn;
price = it.price;		
如图:


而对于func2()无论注不注释上面的两行对程序的结果的都没有影响。是因为func2()的形参为引用,它不会保存为实参的副本。

从bulk = func3()的错误中我们可以发现,派生类可以隐式转换为基类,而反之则不行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值