《C++沉思录》-第四章-类设计者的核查表

设计一个类的时候,需要考虑的问题:


1、你的类需要一个构造函数吗?

可能需要一个构造函数来隐藏内部工作方式。


2、你的数据成员是私有的吗?

保证数据的实时性,有效性。比如长度,如果是共有的,被修改了,就不能正确的表达原先所谓的“长度”。


3、你的类需要一个无参构造函数吗?

没有的话,等于禁止了对象数组。

class Point
{
public:
    Point(int p, int q):x(p),y(q){}
    //...
private:
    int x, y;
};

Point p; //error
Point pa[100]; //error


4、是不是要每个构造函数初始化所有的数据成员?

每个构造函数都要负责为所有的数据成员设置经过明确定义的值。但也未必。


5、类需要析构函数吗?

类是不是分配了资源,而又不能由成员函数自动释放。

特别是的构造函数里包含了new表达式的类,通常要在析构函数中delete掉。


6、类需要一个虚析构函数吗?

决不会作为基类的类是不需要虚析构函数的:任何虚函数只有在继承的情况下才有用。

虚析构函数通常是空的。

struct B
{
    string s;
    virtual ~B() {}
};

struct D : B
{
    string t;
};

int main()
{
    B* bp = new D;
    delete bp; //除非B有一个虚析构函数,否则会调用错误的析构函数。
}

7、你的类需要复制构造函数吗?

关键在于复制该类的对象是否就相当于复制该数据成员和基类对象。

如果你的类在构造函数内分配资源,则可能需要一个显示的复制构造函数来管理资源。

有析构函数(除了空的虚析构函数外)的类通常是用析构函数来释放构造函数分配的资源。

如果不想用户能够复制类的对象,就声明复制构造函数为私有的。


8、你的类需要一个赋值操作符吗?

如果需要复制构造函数,同理多半也会需要一个复制操作符。

如果不想用户能够设置类中的对象,就将赋值操作符私有化。

类X的辅助由X::operator=来定义。通常,operator=应该返回一个X&,

并且由 “return *this;” 结束,来保证与内建的复制操作符一致。


9、你的复制操作符能正确地将对象赋给对象本身吗?

思考一下类他String:

#include <iostream>
#include <string.h>
using namespace std;

class String
{
public:
    String& operator=(const String& s);
private:
    char* data;
};
我们很容易就用下面的方法来实现赋值:

String& String::operator=(const String& s)
{
    delete []data;
    data = new char[strlen(s.data)+1];
    strcpy(data, s.data);
    return *this;
}

可是一旦我们把一个String对象赋值给它本身,那就会彻底失败。

因为s和*this都是指向同一个对象。

//正确的实现方法1

String& String::operator=(const String& s)
{
    if (&s != this)
    {
        delete []data;
        data = new char[strlen(s.data)+1];
        strcpy(data, s.data);
    }
        return *this;
}

//正确的实现方法2

String& String::operator=(const String& s)
{
    char* newdata = new char[strlen(s.data)+1];
    strcpy(newdata, s.data);
    delete []data;
    data = newdata;
    return *this;
}


10、你的类需要定义关系操作符吗?

只要用户想创建你的类型的有序集合,你就必须提供关系操作符。


11、删除数组时你记得用delete[ ]吗?


12、记得复制构造函数和赋值操作符的参数类型中加上const了吗?

类X的复制构造函数应该类似: X::X(const X&)。

赋值应该类似:X::operator=(X&)。


13、如果函数有引用参数,他们应该是const引用?

只有当函数想改变参数时,它才应该有不用const声明的引用参数。

所以,例如,不应该用

Complex operator+(Complex& x, Complex& y);

而应该用

Complex operator+(const Complex& x, const Complex& y);

除非你想允许增加两个Complex对象来改变他们的

值!

否则,由于x+y不是左值,只是一个零时对象,就不能绑定一个非const引用到本身,

只能将其办定到const对象的引用上。

所以类似于x+y+z的表达式就不可用了。

PS: 不理解这句话的同学,可以看这个链接:

http://bbs.csdn.net/topics/360011369


14、记得适当地声明成员函数为const的了吗?

如果确信一个成员函数不能修改它的对象,就可以声明它为const,

这样就把它用于const了。

//错误代码1

#include <iostream>
using namespace std;

class Pen
{
public:
    Pen()
    {
        length = 10;
    }
    int Length()
    {
        return length;
    }
private:
    int length;
};

int main()
{
    const Pen p1;
    cout << "length of p1 : " << p1.Length() << endl;
    return 0;
}
error: passing 'const Pen' as 'this' argument of 'int Pen::Length()' discards qualifiers [-fpermissive]

//正确代码2

#include <iostream>
using namespace std;

class Pen
{
public:
    Pen()
    {
        length = 10;
    }
    int Length() const
    {
        return length;
    }
    int Lenght()
    {
        return length;
    }
private:
    int length;
};

int main()
{
    const Pen p1;
    cout << "length of p1 : " << p1.Length() << endl;

    Pen p2;
    cout << "length of p2 : " << p2.Length() << endl;

    return 0;
}
//length of p1 : 10
//length of p2 : 10

不理解的同学,可以参考这条链接:

http://www.cnblogs.com/this-543273659/archive/2011/07/18/2109922.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值