除非有好的理由否则应该让你的types的行为与内置types一致请拿ints做范本提供行为一致的接口阻止误用的办法包括建立新类型限制类型上的操作束缚对象值比如要统计年月日限制月的大小在1-12消除客户的资源管理责任智能指针shared_ptr支持定制型删除器可被用来自动解除互斥锁等宁以pass-by-reference-to-const替换pass-by-value值传递要调用copy构造函数释放时要调用多次析构函数有副本费时const的必要性引用传递代替值传递时确保不会对传入的数据做改变防止被切割1234567891011classWindow{public:virtualvoiddisplay();}classWindowWithScrollBars:publicWindow{public:virtualvoiddisplay();}voidshow(Window w){w.display();}当用一个WindowWithScrollBars对象传入show时因为是值传递会导致其特化信息被切割变成了一个Window对象无法多态了应该如下传进来的窗口是什么类型w就表现出哪种特性123voidshow(constWindow w){...}说到底引用是指针实现出来的引用传递说到底也是传递的指针如果有一个对象属于内置类型值传递效率会比引用传递效率高一些。值传递对于内置类型和STL的迭代器和函数对象来说代价不贵其他类型还是选用const引用传递好必须返回对象时别妄想返回reference不是所有情况都是引用传递好1234constA operator*(constA rhs){A result(rhs);//调用构造函数returnresult;}返回了一个result的引用但result是一个局部变量离开作用域就被析构了引用不能返回一个局部对象否则一败涂地一个必须返回新对象的函数的做法是就让他返回一个新对象呗1234constA operator*(constA rhs){A result(rhs);//调用构造函数returnA(rhs);}承受一个operator*构造和析构函数的代价即可绝对不要返回一个指针或引用指向一个local stack对象出作用域会被析构或返回引用指向一个heap-allocated对象无法保证合理的delete或返回指针或引用指向一个local static对象而有可能同时需要多个这样的对象一个指针修改了指向对象的参数后其他指针指向的参数也被修改了将成员变量声明为private语法一致性成员变量不是public用户只能通过public里的相应函数来访问成员变量用户使用时就都有一致的使用规则全都要使用小括号等使用函数可以对成员变量的处理有更精确的控制如可以编写const函数实现只读访问不加const实现读写访问等封装性防止成员变量被更改假如有一个public成员变量我们最终取消了它所有使用它的代码都会被破坏假如有一个protected成员变量我们最终取消了它所有使用它的派生类都会被破坏。因此protected其实并不比public更加具有封装性说到底选择private就好以non-member non-friend替换member函数能够访问private成员变量的函数只有class的member函数加上friend函数如果要在一个member函数不只可以访问private数据也能取用private函数、enums、typedefs等和一个non-membernon-friend函数做抉择较好封装性的时后者。因为它并不增加能够访问class内private成分的函数数量将所有便利函数放在多个头文件内但同属于一个命名空间用户可以轻松添加这一组便利函数即可以添加更多的non-membernon-friend函数到此命名空间参考C标准程序库vector、algorithm等导入头文件再进行调用即可完成很多事情non-member若所有参数皆需要类型转换请为此采用non-member函数12345678910classRational{public:Rational(intnumerator0,intdenominator1);intnumerator()const;intdenominator()const;constRational operator* (constRational rhs)const;}Rational onehalf(1,2);Rational resultonehalf*2;//很好Rational result2*onehalf;//不行原因在于12resultonehalf.operator*(2);//发生了隐式转换 得益于之前没有将构造函数声明为explicitresult2.operator*(onehalf);2没有相应的class没有operator*成员函数当然无法执行结论为只有当参数被列于参数列内这个参数才是隐式转换的合格参与者改变做法为将operator*变成non-member函数允许编译器在每个实参上执行隐式转换operator*是否应该成为class的一个friend函数呢否定的因为operator*完全可以借用Rational的public接口完成任务这告诉我们member函数的反面是non-member而不是friend如果你需要为某个函数的所有参数包括this指针所指的那个隐喻参数进行类型转换那么这个函数必须是non-member考虑写出一个不抛出异常的swap函数当做swap时如果交换内部的指针效率就高了呀以指针指向一个对象内含真正的数据即pimpl手法pointer to implementation1234567891011121314151617181920212223classWidgetImpl{public:...private:inta,b,c;}classWidget{public:voidswap(Wideget other){usingstd::swap;//必要的在找不到class里的swap函数调用此函数swap(p,other.p);}private:WidgetImpl* p;}//修订后的std::swap特化版本namespacestd{templatevoidswapWidget(Widget a,Widget b){a.swap(b);//调用a的swap成员函数}}这种方法和STL有一致性因为STL也提供有public的成员函数和std::swap的特化版本如果swap的默认版本的效率你可以接受那不需要做任何事如果swap的默认版本实现效率不足1、提供一个public swap成员函数让它高效的置换两个对象pimpl2、在class的命名空间内提供一个non-member swap并用它调用上诉swap成员函数。3、如果正在编写一个class为class特化std::swap并用它调用你的swap成员函数。
C++设计与声明超详细讲解
除非有好的理由否则应该让你的types的行为与内置types一致请拿ints做范本提供行为一致的接口阻止误用的办法包括建立新类型限制类型上的操作束缚对象值比如要统计年月日限制月的大小在1-12消除客户的资源管理责任智能指针shared_ptr支持定制型删除器可被用来自动解除互斥锁等宁以pass-by-reference-to-const替换pass-by-value值传递要调用copy构造函数释放时要调用多次析构函数有副本费时const的必要性引用传递代替值传递时确保不会对传入的数据做改变防止被切割1234567891011classWindow{public:virtualvoiddisplay();}classWindowWithScrollBars:publicWindow{public:virtualvoiddisplay();}voidshow(Window w){w.display();}当用一个WindowWithScrollBars对象传入show时因为是值传递会导致其特化信息被切割变成了一个Window对象无法多态了应该如下传进来的窗口是什么类型w就表现出哪种特性123voidshow(constWindow w){...}说到底引用是指针实现出来的引用传递说到底也是传递的指针如果有一个对象属于内置类型值传递效率会比引用传递效率高一些。值传递对于内置类型和STL的迭代器和函数对象来说代价不贵其他类型还是选用const引用传递好必须返回对象时别妄想返回reference不是所有情况都是引用传递好1234constA operator*(constA rhs){A result(rhs);//调用构造函数returnresult;}返回了一个result的引用但result是一个局部变量离开作用域就被析构了引用不能返回一个局部对象否则一败涂地一个必须返回新对象的函数的做法是就让他返回一个新对象呗1234constA operator*(constA rhs){A result(rhs);//调用构造函数returnA(rhs);}承受一个operator*构造和析构函数的代价即可绝对不要返回一个指针或引用指向一个local stack对象出作用域会被析构或返回引用指向一个heap-allocated对象无法保证合理的delete或返回指针或引用指向一个local static对象而有可能同时需要多个这样的对象一个指针修改了指向对象的参数后其他指针指向的参数也被修改了将成员变量声明为private语法一致性成员变量不是public用户只能通过public里的相应函数来访问成员变量用户使用时就都有一致的使用规则全都要使用小括号等使用函数可以对成员变量的处理有更精确的控制如可以编写const函数实现只读访问不加const实现读写访问等封装性防止成员变量被更改假如有一个public成员变量我们最终取消了它所有使用它的代码都会被破坏假如有一个protected成员变量我们最终取消了它所有使用它的派生类都会被破坏。因此protected其实并不比public更加具有封装性说到底选择private就好以non-member non-friend替换member函数能够访问private成员变量的函数只有class的member函数加上friend函数如果要在一个member函数不只可以访问private数据也能取用private函数、enums、typedefs等和一个non-membernon-friend函数做抉择较好封装性的时后者。因为它并不增加能够访问class内private成分的函数数量将所有便利函数放在多个头文件内但同属于一个命名空间用户可以轻松添加这一组便利函数即可以添加更多的non-membernon-friend函数到此命名空间参考C标准程序库vector、algorithm等导入头文件再进行调用即可完成很多事情non-member若所有参数皆需要类型转换请为此采用non-member函数12345678910classRational{public:Rational(intnumerator0,intdenominator1);intnumerator()const;intdenominator()const;constRational operator* (constRational rhs)const;}Rational onehalf(1,2);Rational resultonehalf*2;//很好Rational result2*onehalf;//不行原因在于12resultonehalf.operator*(2);//发生了隐式转换 得益于之前没有将构造函数声明为explicitresult2.operator*(onehalf);2没有相应的class没有operator*成员函数当然无法执行结论为只有当参数被列于参数列内这个参数才是隐式转换的合格参与者改变做法为将operator*变成non-member函数允许编译器在每个实参上执行隐式转换operator*是否应该成为class的一个friend函数呢否定的因为operator*完全可以借用Rational的public接口完成任务这告诉我们member函数的反面是non-member而不是friend如果你需要为某个函数的所有参数包括this指针所指的那个隐喻参数进行类型转换那么这个函数必须是non-member考虑写出一个不抛出异常的swap函数当做swap时如果交换内部的指针效率就高了呀以指针指向一个对象内含真正的数据即pimpl手法pointer to implementation1234567891011121314151617181920212223classWidgetImpl{public:...private:inta,b,c;}classWidget{public:voidswap(Wideget other){usingstd::swap;//必要的在找不到class里的swap函数调用此函数swap(p,other.p);}private:WidgetImpl* p;}//修订后的std::swap特化版本namespacestd{templatevoidswapWidget(Widget a,Widget b){a.swap(b);//调用a的swap成员函数}}这种方法和STL有一致性因为STL也提供有public的成员函数和std::swap的特化版本如果swap的默认版本的效率你可以接受那不需要做任何事如果swap的默认版本实现效率不足1、提供一个public swap成员函数让它高效的置换两个对象pimpl2、在class的命名空间内提供一个non-member swap并用它调用上诉swap成员函数。3、如果正在编写一个class为class特化std::swap并用它调用你的swap成员函数。