本意是要设计一个存储表的内存结构,可是要求又比较奇特:既能提供类似vector的调用方式,又能有map的特性。于是自己设计了一个怪模怪样的类:
class Table
{
std::vector<std::vector<std::string> > talbe_;
public:
Table();
int find(const int index, const char* value);
std::vector<std::string>& operator[](const int index);
int size();
int column_num();
};
但是这样使用时,主类的调用接口如果传递的是引用,比如下面这样:
int get_table(const char* table_name, Table& table);
这里虽然传递了引用,仍然涉及一些内存拷贝的事情,而且构造一个这样的对象,开销本是不必要的,而如果使用一个指针的引用,比如:
int get_table(const char* table_name, Table*& table);
这样使用时会出现 (*table)[index]这样怪异的写法。
后来总算想到一种办法,将class Table中的 table_换为一个index,而Table由于要调用一些主类中的数据,因此将Table声明为主类的friend。
大致是这样的:
class Table
{
int index_;
public:
Table();
int find(const int index, const char* value);
std::vector<std::string>& operator[](const int index);
int size();
int column_num();
};
class ConfManager
{
friend class Table;
std::vector<std::string> conf_file_array_;
std::vector<std::string> so_file_array_;
std::vector<std::vector<std::vector<std::string> > > table_array_;
};
本来以为是万事大吉,可是主类中要设置Table时,又需要访问Table::index_,提供一个set方法又不好,因此,只能再把主类作为Table的friend。这样以来,又混乱不堪了。
最后灵光一闪,将Table作为主类的一个内部类,同时,将主类作为Table的friend类,这样大家都可以访问私有成员,而对于用户却又是透明的。如下:
class ConfManager
{
std::vector<std::string> conf_file_array_;
std::vector<std::string> so_file_array_;
std::vector<std::vector<std::vector<std::string> > > table_array_;
std::vector<std::string> table_name_array_;
public:
class Table
{
friend class ConfManager;
int index_;
public:
Table();
int find(const int index, const char* value);
std::vector<std::string>& operator[](const int index);
int size();
int column_num();
};
static ConfManager& get_conf_manager();
};
确实有一种浑然天成的味道,为了外面使用方便,再加个typedef,如下:
typedef ConfManager::Table Table;
friend关键字,在effective c++中被诟病再三,主要原因是它破坏了程序的封装性。不过万事万物都有它存在的必要性,话说回来,依赖于class,private,protected,等等所维护的封装性,都只存在于编译期而已。真正让人头疼的,还是运行起来的各种越界和泄漏。
原文时间(2014-3-13)