您的位置:首页 > 理论基础 > 数据结构算法

类的基本结构

2006-01-26 14:43 204 查看
今天早上看了一本数据结构的书关于类和动态存储的章节。书里面大概地举了几个关于在一个类里面动态申请内存的例子。我由此想到就算是一个一般的类也应该具备一定的基本结构,而并不不是一个类头、几个数据成员和成员函数就可以作为一个类“安全”地使用。

 

    我们先看一些例子。

 

以前,我看到过有很多人这样写一个类:

class A

{

public:

    int GetCount(){return ++m_count;}

private:

    int m_count;

};

编写者目的是获得A类对象调用成员函数GetCount的次数。

结果是获得一个很小的负数!当然这是一个很低级的错误,现在已经没有谁会范的了。

 

哈哈,所以我的第一个结论是:一个类应该有一个用户自定义的默认构造函数。另外,在我的VC6.0编译器中,如果一个类有多个构造函数(但是没有一个默认构造函数,即没有一个不带参数的构造函数),它是不会为你自动加上去的,所以自定义的默认构着函数应该是每一个类都应该有的。

 

于是改为:

class A

{

public:

    A() {m_count = 0;}

    int GetCount(){return ++m_count;}

private:

    int m_count;

};

错误就消失了。
但是加了一些功能以后,另一个错误又出现了。
class B
{
public:
       B(){m_count = 0; m_pstr = 0x0;}
       B(const string &str);
      
       int GetInt() {return m_count;}
 

private:
       int m_count;
       string *m_pstr;
};
 

//////////////////////////////////////////////////////////////////////////
B::B(const string &str) {
       m_count = 0;
       m_pstr = new string(str);
}
 

如果有一下语句:
//这条B obj1(“string”)语句在VC6.0中不会出现错误,但在C++Builder中就会出现错误,具、、//体原因可以查看具体编译器的帮助文档。本文最后也概略讲一下。不同编译器有不同的实//现。

B obj1(“string”),obj2 = obj1;
 

以上语句只是告诉编译器要吧obj1的信息安位拷贝到obj2中。结果执行语句后,obj2的m_pstr和obj1的m_pstr成员指向同一块内存地址。显然这不是我们想要的结果。如果在较复杂的程序中使用就会埋下隐蔽的祸患。
所以我的第二个结论是:一个类应该有一个复制构造函数详细地告诉编译器如何复制(初始化)一个自定义对象。这样才能使用户自定义类型使用起来能够更加“像”C++内部类型,这也许是C++“美丽“的地方之一吧^_^。

 

哈哈!是不是就完美无缺呢?Of course not.我们还漏了释放B类型中动态创建的对象*m_pstr。这个工作要在析构函数中完成。

 

于是又修改为

class B
{
public:
       B(){m_count = 0; m_pstr = 0x0;}
       B(const string &str);
       B(const B &obj);
       virtual ~B();
      
       int GetInt() {return m_count;}
 

private:
       int m_count;
       string *m_pstr;
};
//////////////////////////////////////////////////////////////////////////
B::B(const string &str) {
       m_count = 0;
       m_pstr = new string(str);
}
 

B::B(const B &obj) {
       m_count = 0;
       m_pstr = new string(*obj.m_pstr);
}
 

B::~B(){
       delete m_pstr;
       m_pstr = 0x0;
}
 

 

其实,我觉得最好是把复制构造函数的孪生子妹operator=函数写上。这样能够使类无论是初始化还是赋值的时候能够正确执行。特别是上面举的有动态内存分配的情况下,就更加应该有这个重载函数。否则当对象作为形式参数传递给函数的时候就有可能出错。就如下面的情况:
int main(void) {
       {
B obj0;
{
                     B obj1 = obj0;
              }
}//在这里将出现运行期的错误!因为obj0中的*m_pstr已经在这之前被释放掉。
}
      
 

       这是我一点心得。

语句
B obj1(“string”);
在VC6.0中等价于
B obj1(string(“string”));
VC6.0自动用串”string”生成一个string类型的临时对象并传递给B的构造函数。
但是在C++Builder中没有这种功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息