C++面向对象与堆栈内存管理(四)

在C++中写面向对象程序与用其他的完全面向对象语言来编写程序有很大不同,根本原因在于——C++只传递值,不传递对象。事实上,这种不同应该归类为“不完全面向对象的语言”和“完全的面向对象语言”的区别之处,C++只是作为前者中的一个代表。

本系列文章以一个简单的数据库类为例,由浅入深,逐渐体会这种“完全”和“不完全”之间的差异。

文章的目标人群是C++初学者。写作目的,一是阐述这种“完全”和“不完全”之间的差异,二是希望在分析这一案例的过程中,加深大家对于面向对象中“封装、继承、多态”的理解,帮助大家学习面向对象的思想。

博主同样也是编程的新人,如果有任何疏漏之处,请多多包涵,不吝赐教。

 #4.0 回归C风格的写法

//返璞归真,回归C风格

#include <iostream>
#include <vector>
#include <string>
#include <fstream>

using namespace std;
/*以数据库类为例
c风格的原则:向变量看齐
一切都是深拷贝*/

/*类中要注意的几个成员:
默认构造函数、拷贝构造函数、析构函数、赋值函数
这些默认是成员级的深拷贝,唯一要改的情况就是成员中有指向堆的指针
这几个函数不写也默认会有,所以特别注意如果你不写的话是否符合风格*/

class Record
{
	friend ostream& operator<<(ostream& out, const Record& rhs);
public:
	unsigned int id;
	unsigned int gpa;
	string name;
};

ostream& operator<<(ostream& out, const Record& rhs)
{
	out << rhs.id << ' ' << rhs.name << ' ' << rhs.gpa << endl;
	return out;
}

class Database
{
public:
	~Database()
	{
		//因为vector管理的是指针,所以需要重写析构函数
		//遵循insert的两个约定,_datatab中所有对象应该都在堆内存中
		for (size_t i = _datatab.size() - 1; i != -1; --i)
		{
			delete _datatab[i];
		}
	}
	void insert(const Record& rec)
	{
		//google代码规范:只传递常量引用
		//传递对象,就拷贝到堆中再插入
		//主要防止用户在栈中创建Recrod插入数据库
		_datatab.push_back(new Record(rec));
	}
	void insert(Record* prec)
	{
		//传递指针,就直接将prec的内容插入进去
		_datatab.push_back(prec);
	}
	Record& operator[](size_t index)
	{
		//返回真引用,在返回时
		//在赋值时,也不会导致内存泄漏,因为调用的是Record的拷贝函数
		//而如果我们严格遵照c风格,record的所有拷贝函数都是深拷贝
		return *_datatab[index];
	}

private:
	vector<Record*> _datatab;//要保证vector中的指针指向的是仅属于数据库自己的堆对象
	//vector管理的值总是深拷贝,如果record比较大,那vector赋值就很慢
};

Database* import_file1(string file_path)
{
	//如果有菜鸟不懂个中奥妙,这么玩也不会错,但是速度就很慢了
	ifstream fin(file_path);
	Database* db = new Database();
	Record temp;
	while (fin >> temp.id >> temp.name >> temp.gpa)
	{
		db->insert(temp);//深拷贝
	}
	return db;
}

Database* import_file(string file_path)
{
	//能打败Python的写法
	ifstream fin(file_path);
	Database* db = new Database();
	Record* temp = new Record;
	while (fin >> temp->id >> temp->name >> temp->gpa)
	{
		db->insert(temp);//浅拷贝
		temp = new Record;
	}
	delete temp;//删去最后一次空的堆对象
	return db;
}

int main()
{
	//我们的建议是,堆对象不要用引用直接操作,要使用指针间接操作
	//用指针始终表面它是在堆中,防止与栈中混淆
	Database* db = import_file("./RawData.txt");
	for (int i = 0; i < 10; ++i)
	{
		cout << db->operator[](i);
	}
	delete db;//别忘了释放对象
}

发布了9 篇原创文章 · 获赞 6 · 访问量 1119

猜你喜欢

转载自blog.csdn.net/u014132143/article/details/90212694