细读《Effective C++》之四

news/2024/10/3 3:26:21

Chapter 4. Designs and Declarations

什么样的接口是你应该提供给client的?或者,换句话说:什么样的接口是你希望被提供的?

If an attempted use of an interface won't do what the client expects, the code won't compile; and if the code does compile, it will do what the client wants.

如果你的programs不是写给你自己用,就应该实现上面的要求。

Item 18 - 25

条款18:Make interfaces easy to use correctly and hard to use incorrectly

想满足“易用难错”这样苛刻的要求,从编程的角度来看并不难。问题是随着你对接口及数据要求的增加,整个代码也将变得很冗繁,寻找到一个平衡点即可。

条款19:Treat class design as type design

How should objects of your new type be created and destroyed? 构造、析构、分配、释放。

How should object initialization differ from object assignment? 初始化 != 赋值,因为构造 != 赋值。

What does it mean for objects of your new type to be passed by value? 这基本意味着你要重写copy constructor。

What are the restrictions on legal values for your new type? 我们的codes在大多数情况下就是为了验证和处理约束条件及其引发的异常,这些工作应该在构造、赋值时被很好地完成。

Does your new type fit into an inheritance graph? 主要是要考虑virtual function和virtual destructor。

What kind of type conversions are allowed for your new type?

What operators and functions make sense for the new type? 成员、友元、静态?

What standard functions should be disallowed? 要么将其声明为private(不是万无一失的),要么就private继承一个Uncopable类。

Who should have access to the members of your new type? private、protected、public、friend?

What is the "undeclared interface" of your new type?

How general is your new type? 要想充分一般化,就用class template。

Is a new type really what you need? 冷静,看看GoF的DP。

条款20:Prefer pass-by-reference-to-const to pass-by-value

by value还是by reference的根本区别在于效率和安全。所谓效率体现在by reference避免了copy,而安全则体现在避免了slicing(对象切割)。将一个derived class iobject以by value传给base class object将发生slicing。

需要注意的是,对于build-in type、STL迭代器和函数对象最好还是用by value。

条款21:Don't try to return a reference when you must return an object

const Rational& operator*(const Rational& lhs,   // warning! bad code!
                          const Rational& rhs)
{
  Rational result(lhs.n 
* rhs.n, lhs.d * rhs.d);
  
return result;
}


const Rational& operator*(const Rational& lhs,    // warning! more bad
                          const Rational& rhs)    // code!
{
  Rational 
*result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
  
return *result;
}


Rational w, x, y, z;
= x * y * z;                     // same as operator*(operator*(x, y), z)

const Rational& operator*(const Rational& lhs,    // warning! yet more
                          const Rational& rhs)    // bad code!
{
  
static Rational result;             // static object to which a
                                      
// reference will be returned
  result = ... ;                      // multiply lhs by rhs and put the
                                      
// product inside result
  return result;
}


bool operator==(const Rational& lhs,            // an operator==
                const Rational& rhs);           // for Rationals
Rational a, b, c, d;
...
if ((a * b) == (c * d))  {
    
do whatever's appropriate when the products are equal;
}
 else    {
    
do whatever's appropriate when they're not;
}


if (operator==(operator*(a, b), operator*(c, d)))

// the right way
inline const Rational operator*(const Rational& lhs, const Rational& rhs)
{
  
return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

条款22:Declare data members private

我知道public不可取,但我觉得用protected对子类是一种方便。

条款23:Prefer non-member non-friend functions to member functions

自从开始用C++,我自己在写代码的时候,几乎再没用过non-member non-friend函数。有时候coding纯粹是coding,没有任何比较和规划,写哪儿是哪儿。Scott提醒了我:coding的时候要记得什么才是真正的OO。

条款24:Declare non-member functions when type conversions should apply to all parameters

If you need type conversions on all parameters to a function (including the one pointed to by the this pointer), the function must be a non-member.

记得在社区的一篇帖子里回答一个关于友元的问题的时候,我曾经这样说:

任何时候都最好不要用,包括ops。

所谓friend,就是可以帮你的忙,但是有代价:代价就是他了解了你的情况,can access your resources. 破坏了封装性,故称“白箱复用”。

如果实在不能通过自身的class实现功能,就用:Adaptor(具体参考GoF的<Design Patterns>).

当然,如果你觉得用Adaptor很麻烦,那么,在你想access你本来无法access的resources的时候,你就使你成为他的friend。

这就是它的好处,也是它的坏处。

条款25:Consider support for a non-throwing swap

namespace std {
  template
<typename T>          // typical implementation of std::swap;
  void swap(T& a, T& b)         // swaps a's and b's values
  {
    T temp(a);
    a 
= b;
    b 
= temp;
  }

}


class Widget {                     // same as above, except for the
public:                            // addition of the swap mem func
  ...
  
void swap(Widget& other)
  
{
    
using std::swap;               // the need for this declaration
                                   
// is explained later in this Item
    swap(pImpl, other.pImpl);      // to swap Widgets, swap their
  }
                                // pImpl pointers
  ...
}
;

namespace std {
  template
<>                       // revised specialization of
  void swap<Widget>(Widget& a,     // std::swap
                    Widget& b)
  
{
    a.swap(b);                     
// to swap Widgets, call their
  }
                                // swap member function
}


namespace WidgetStuff {
  ...                                     
// templatized WidgetImpl, etc.
  template<typename T>                    // as before, including the swap
  class Widget { ... };                   // member function
  ...
  template
<typename T>                    // non-member swap function;
  void swap(Widget<T>& a,                 // not part of the std namespace
            Widget<T>& b)                                         
  
{
    a.swap(b);
  }

}


template
<typename T>
void doSomething(T& obj1, T& obj2)
{
  
using std::swap;           // make std::swap available in this function
  ...
  swap(obj1, obj2);          
// call the best swap for objects of type T
  ...
}
 


 

https://dhexx.cn/news/show-3954105.html

相关文章

【BZOJ】[HAOI2015]树上操作-DFS序

传送门&#xff1a;点击打开链接 题意&#xff1a; 有一棵点数为 N 的树&#xff0c;以点 1 为根&#xff0c;且树点有边权。有 M 个操作&#xff0c;分为三种&#xff1a; 操作 1 &#xff1a;把某个节点 x 的点权增加 a 。 操作 2 &#xff1a;把某个节点 x 为根的子树中所…

[POJ3525]Most Distant Point from the Sea(二分+半平面交)

题目&#xff1a; 我是超链接 题意&#xff1a; 给出一个多边形&#xff0c;求里面一个点&#xff0c;其距离离多边形的边界最远&#xff0c;输出距离。 题解&#xff1a; 二分答案&#xff0c;相当于是把所有直线往里平移mid长&#xff0c;看看这个半平面能不能有交点 这…

(翻譯) 註解程式碼的13個建議 (C/C++)

摘要 :轉載13個註解程式碼的方法&#xff0c;讓程式碼更容易看懂 Introduction轉載出處 : http://www.cnblogs.com/oomusou/archive/2008/04/26/1172208.html 1.Comment each level對每一層級採用統一的方式注釋每個程式碼區塊&#xff0c;例如&#xff1a; *為每個class&a…

细读《Effective C++》之五

Chapter 5. Implementations 如果说对于对象模型的深刻理解是为了更好地设计和声明&#xff0c;那么对于实现的斤斤计较则是为了更高的效率。 Item 26 - 28 条款26&#xff1a;Postpone variable definitions as long as possible 不要过早地定义变量&#xff0c;直到真正需…

[POJ3384]Feng Shui(半平面交+凸包)

题目&#xff1a; 我是超链接 题意&#xff1a; 在一个凸多边形中放两个半径固定的圆&#xff0c;要求输出使覆盖面积最大的&#xff08;可重叠&#xff09;两个圆圆心 题解&#xff1a; Emmm。。。套路缩小凸多边形&#xff0c;形成的凸包是圆心可以在的位置&#xff0c;…

【后缀数组】不同子串

【题目描述】 给定一个由小写英文字母构成的字符串T,求其不同子串个数。 【输入】 一个字符串&#xff0c;长度不超过100000。 没有传送门…… 裸的后缀数组&#xff1a;所有子串就是各个后缀字符串的前缀&#xff0c;所以答案就是每一个后缀字符串的长度减去与前一个重复…

细读《Effective C++》之六

Chapter 5. Implementations Item 29 - 31 条款29&#xff1a;Strive for exception-safe code voidPrettyMenu::changeBackground(std::istream&imgSrc)...{ lock(&mutex); // acquire mutex (as in Item 14) delete bgImage; …

[BZOJ2732][HNOI2012]射箭(二分+半平面交)

题目&#xff1a; 我是超链接 题解&#xff1a; 这个关卡包含前面的特性很明显是二分 判断的话随便画画柿子就有y1<ax2bx<y2&#xff0c;而x,y1,y2都是已知的&#xff0c;这不就是一个关于a,b的直线了吗&#xff0c;半平面交&#xff1f; 这个数据范围也只有nlogn的…

textmate bundle for jquery

原文地址:TextMate Bundle for jQuery使用这个bundle的例子:键入ready然后按tab就会生成下面的代码:$(document).ready(function() {});其中第二行被选中,这时在里面编写jquery代码即可.如果要查看某个function的官方文档的话可以在键入的function之后使用快捷键ctrlh查看.关于…

【洛谷】分梨子

传送门&#xff1a;点击打开链接 题意&#xff1a; 每个梨子都具有两个属性值&#xff0c;Ai和Bi。设在选出的梨子中&#xff0c;两个属性的最小值分别是A0和B0。对于所有被选出的梨子i&#xff0c;都满足C1*(Ai-A0)C2*(Bi-B0)≤C3&#xff08;其中&#xff0c;C1、C2和C3都是…