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

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

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

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

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

#0.0 Python的代码示例

以下是用Python实现的数据库,作为一个完全面向对象语言的例子,后面我们要以此为目标用C++实现同样的功能。

#先看python的优雅之处
class Record:
    #记录类
    def __init__(self):
        self.name = None
        self.id = None
        self.gpa = None
        return
    def __repr__(self):
        return str(self.id) + ' ' + self.name + ' ' + str(self.gpa)

class Database:
    #数据库类
    def __init__(self):
        self._datatab = []
        return
    def __getitem__(self,index):
        #[]获得数据的方法
        return self._datatab[index]
    def insert(self,rec):
        #插入新数据的方法
        self._datatab.append(rec)
        return

def import_file(file_path):
    #文件导入函数
    #将文件读取的过程从类独立出来
    #传入文件路径,返回由文件创建好的对象
    fin = open(file_path)
    db = Database()
    for line in fin:
        id,name,gpa = line.split()
        rec = Record()
        rec.id = int(id)
        rec.name = name
        rec.gpa = int(gpa)
        db.insert(rec)
    return db #把导入成功的数据库返回

if __name__ == "__main__":
    db = import_file("./RawData.txt")
    for i in range(10):
        #打印前十名
        print(db[i])

#1.0 自然而然的C++实现代码

 如果按照写Python时的思路,我们很容易写以下代码

//首先很自然地按照写py面向对象的方法来写c++

#include <iostream>
#include <fstream>
#include <string>
#include <vector>//模仿py中list

using namespace std;

//记录类
class Record
{
	friend ostream& operator<<(ostream& out, const Record& rec);//模仿py的__repr__函数
public:
	unsigned int id;
	unsigned int gpa;
	string name;
};
ostream& operator<<(ostream& out, const Record& rec)
{
	out << rec.id << ' ' << rec.name << ' ' << rec.gpa << endl;
	return out;
}

//数据库类
class Database
{
public:
	Record& operator[](size_t index)
	{
		return _datatab[index];
	}
	void insert(Record rec)
	{
		_datatab.push_back(rec);
	}

private:
	vector<Record> _datatab;
};

//文件导入函数
Database import_file(string file_path)
{
	ifstream fin(file_path);
	Database db;
	Record temp;
	while (fin >> temp.id >> temp.name >> temp.gpa)
	{
		db.insert(temp);
	}
	return db;
}

int main()
{
	Database db = import_file("./RawData.txt");
	for (int i = 0; i < 10; ++i)
	{
		cout << db[i];
	}
}

程序运行没错,问题在于,使用计时函数测出前Python程序的耗时为0.03s,而普遍认为“更快”的C++却花了0.1s左右(实际上,测试结果受诸多因素影响,尤其是在读文件阶段,受影响较大,单纯比较时间实际上没有意义,这里只是引出问题而已)

/*总结:
运行倒是没错,怎么会那么慢呢?!
一般不都认为是C++更快吗?如此这样,快在哪里呢?*/

/*问题所在:
因为在C++程序中,传递的不是“对象”,而是“变量”,是大段的数据块
在43行导入函数中,实际发生的情况不是创建一个Database对象->把数据插入进去->把处理好的数据库返回
而是:创建一个Database对象->把数据插入进去->把处理好的数据库拷贝到右值->释放原来那个Database的栈空间->把右值返回
也就是说,处理好数据后竟要再做一次完全无意义的拷贝!
对于像数据库那么大块的数据,这一次拷贝所占用的时间将无法忽略*/

/*更多:
其实在这一程序中,这种拷贝对象产生的无意义时间浪费还有:
33行 insert 函数,传入时会进行一次对象拷贝,插入到vector时再拷贝一次,虽然一个Record对象很小,但是数量多了时间代价仍然很大*/

/*最后:
这一切问题的原因,其实很简单:“C++程序不传递对象,只传递变量(值)”
这就比方说你是个木匠,有人请你做一台桌子,你设计好、锯好、雕好后,等到交给别人手上的前一瞬间,却按照已经做好的桌子又复制了一台,非要把原本的桌子拆了,把复制品给人家
这就是C++写面向对象的难解之处,同时也是所有不完全面向对象语言写面向对象程序的共性问题*/

这,就是我们接下来要探究的问题。

下一篇链接:https://blog.csdn.net/u014132143/article/details/90212547

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

猜你喜欢

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