转自:http://hi.baidu.com/a024014/blog/item/617b690ac43e8b1a95ca6ba2.html
类和函数:设计与声明
条款18 :争取使类的接口完整并且最小
条款19 :分清成员函数,非成员函数和友元函数
如果 f 必须是虚函数,就让它成为 C 的成员函数。
operator>> 和 operator<< 决不能是成员函数。如果 f 是 operator>> 或 operator<< ,让 f 成为非成员函数。如果 f 还需要访问 C 的非公有成员,让 f 成为 C 的友元函数。
只有非成员函数对最左边的参数进行类型转换。如果 f 需要对最左边的参数进行类型转换,让 f 成为非成员函数。如果 f 还需要访问 C 的非公有成员,让 f 成为 C 的友元函数。
Eg:
Ostream& operator<<(ostream& output,const String& str){
Output<<String.data;//String 是自己定义的一个类
}
条款20 :避免public 接口出现数据成员
这个条款其实就是让我们用get 方法获取成员而避免把数据成员直接声明为public 。
条款21 :尽可能使用const
Const char *p; 1
Char const *p; 2
Char *const p; 3
Const char *const p; 4
其中1=2 ,表示指针p 指向的内容是不可修改的常量;
而3 表示p 指向的地址是不可修改的;
4 则综合了前两者。基本上就是个就近原则,以* 为分界线,const 靠近谁,谁就是不可修改的。
顺便提下,可以这样声明:
Const int &p=3;//int &p=3; 是错的
Const Char *&const p=”hello”;//const char *&p=”hello” 是错的
另外,C++ 允许仅在const 方面有不同的成员函数重载,eg:
class String {
public:
...
// 用于非 const 对象的 operator[]
char& operator[](int position)
{ return data[position]; }
// 用于 const 对象的 operator[]
const char& operator[](int position) const
{ return data[position]; }
private:
char *data;
};
String s1 = "Hello";
cout << s1[0]; // 调用非 const
// String::operator[]
const String s2 = "World";
cout << s2[0]; // 调用 const
// String::operator[]
当方法为const 时,还要修改数据成员时,可以把数据成员修饰为mutable.
有时候,迫不得已,可以用const_cast 把const 性转掉。
条款22 :尽量用“传引用”而不用“传值”
传递引用除了比传值高效之外,主要原因在于它避免了切割问题的出现,也就是不存在子类用父类变量传递时发生的切割,被去除了子类特有的部分,用引用实现动态绑定。
当然在传递的变量类型很小,或者基类型时,用传值反而更快,因为引用的内部实现其实用的是指针,当char ,short,int ,直接传递值速度反而更快一些。
条款23 :必须返回一个对象时不要试图返回一个引用
该条款主要就是为了保证程序的正确性,防止返回一个局部对象的引用。
条款24 :在函数重载和设定参数缺省值间慎重选择
`
条款25 :避免对指针和数字类型重载
Eg:void f(int x);
Void f(string *ps);
F(0); // 调用f(int) 还是f(string *) ?
上述结果是调用f(int) ,但是有时候我们并不希望编译程序这样理解。
定义一个类NULL 如下可以解决问题:
const // 这是一个 const 对象 ...
class {
public:
template<class T> // 可以转换任何类型
operator T*() const // 的 null 非成员指针
{ return 0; } //
template<class C, class T> // 可以转换任何类型
operator T C::*() const // 的 null 成员指针
{ return 0; }
private:
void operator&() const; // 不能取其地址
// ( 见条款 27)
} NULL; // 名字为 NULL
此时调用f 函数时用f(NULL) 和f(0) 即可区分开来。
当然, 作为重载函数的设计者,归根结底最基本的一条是,只要有可能,就要避免对一个数字和一个指针类型重载。