![](https://img-blog.csdnimg.cn/20191021133445218.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
Effecitve C++
xupeng1644
道阻且长,行则将至!
展开
-
48. Be aware of template metaprogramming
认识template元编程请记住:Template metaprogramming(TMP,模板元编程)可将工作由运行期移到编译器,因而得以实现早期错误检测和更高的执行效率。TMP可被用来生成"基于政策选择组合"(based on combinations of policy choices)的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码。...原创 2020-02-20 16:20:55 · 1238 阅读 · 0 评论 -
47. Use traits for information about types.
请使用traits classes表现类型信息请记住:Traits classes使得"类型相关信息"在编译器可用。它们以template和"template特化"完成实现。整合重载技术(overloading)后,traits classes有可能在编译器对类型执行if…else测试。...原创 2020-02-20 16:17:15 · 1292 阅读 · 0 评论 -
46. Define non-member functions inside templates when type conversions are desired.
需要类型转换时请为模板定义非成员函数请记住:当我们编写一个class template,而它所提供之"于此template相关的"函数支持"所有参数之隐式类型转换"时,请将那些函数定义为"class template内部的friend函数"。...原创 2020-02-20 16:14:30 · 1305 阅读 · 0 评论 -
45. Use member function templates to accept "all compatible types."
运用成员函数模板接受所有兼容类型请记住:请使用member function templates(成员函数模板)生成"可接收所有兼容类型"的函数。如果你声明member templates用于"泛化copy构造"或"泛化assignment操作",你还是需要声明正常的copy构造函数和copy assignment操作符。...原创 2020-02-20 16:11:53 · 1258 阅读 · 2 评论 -
44. Factor parameter-independent code out of templates.
将与参数无关的代码抽离templates请记住:Template生成多个classes和多个函数。所以任何template代码都不该与某个造成膨胀的template参数产生相依关系。因非类型模板参数(non-type template parameters)而造成的代码膨胀,往往可消除,做法是以函数参数或class成员变量替换template参数。因类型参数(type paramte...原创 2020-02-20 16:08:10 · 1435 阅读 · 0 评论 -
43. Know how to access names in templatized base classes.
学习处理模板化基类的名称请记住:可在derived class templates内通过“this->”指涉base class templates内的成员名称,或藉由一个明白写出的"base class资格修饰符"完成。...原创 2020-02-20 16:02:29 · 1345 阅读 · 0 评论 -
42. Understand the two meanings of typename.
了解typename的双重意义以下template声明中,class和typname有什么不同?template<class T> class Widget;template<typename T> class Widget;从C++的角度而言,声明template参数时,不论使用关键字class或typname,意义完全相同。然后C++并不总是把class...原创 2020-02-20 10:19:44 · 1369 阅读 · 0 评论 -
41. Understand implicit interfaces and compile-time polymorphism
了解隐式接口和编译期多态加诸于template参数身上的隐式接口,就像加诸于class对象身上的显示接口一样真实,而且两者都在编译器完成检查。就像你无法以一种“与class提供之显式接口矛盾”的方式来使用对象(代码将通不过编译),你也无法在template中使用“不支持template所要求之隐式接口”的对象(代码一样通不过编译)。请记住classes和templates都支持接口(i...原创 2020-02-20 09:48:52 · 1322 阅读 · 0 评论 -
40. Use multiple inheritance judiciously
明智而审慎地使用多重继承多重继承只是面向对象工具箱里面的一个工具而已。和单一继承比较,它通常比较复杂,使用上也比较难以理解,所以如果有一个单一继承的设计方案,而它大约等价与一个多重继承设计方案,那么单一继承设计方法几乎比较受欢迎。如果你唯一能够提出的设计方案涉及多重继承,应该更努力想一想-几乎可以说一定会有某些方案让单一继承行得通。然而多重继承有时候的确是完成任务值最简洁、最易维护、最合理的...原创 2019-12-20 16:40:41 · 1328 阅读 · 0 评论 -
39. Use private inheritance judiciously
明智而审慎地使用private继承请记住:Private继承意味is-implemented-in-terms of(根据某物实现出)。它通常比复合(composition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。和复合(composition)不同,pr...原创 2019-12-17 14:49:18 · 1283 阅读 · 0 评论 -
38. Model "has-a " or "is-implemented-in-terms-of" through composition
通过复合塑模出has-a或"根据某物实现出"复合(compositon)是类型之间的一种关系,当某种类型的对象内含它种类型的对象,便是这种关系。例如:class Address { ... };class PhoneNumber { ... };class Person {public: ...private: std::string name; Addresss add...原创 2019-12-16 11:08:05 · 1269 阅读 · 0 评论 -
37. Never redefine a function's iherited default parameter value.
绝不重新定义继承而来的缺省参数值virtual函数是动态绑定,而缺省参数是静态绑定。class Shape{public: enum ShapeColor {Red, Green, Blue }; virtual void draw(ShapeColor color = Red) const = 0; ...};class Rectangle : public Shape...原创 2019-12-14 10:15:30 · 1327 阅读 · 0 评论 -
36. Never redifine an inherited non-virtual function
绝不重新定义继承而来的non-virtual函数class B{public: void mf(); ...};class D : public B{ ...}有以下调用:D x;bB* pB = &x;pB->mf(); // line1D* pD = &x;pD->mf(); // line2line1、line2都...原创 2019-12-10 15:09:15 · 1408 阅读 · 0 评论 -
35. Consider alternatives to virtual functions
考虑virtual函数以外的其他选择请记住:virtual函数的替代方案包括NV1手段及Stratery设计模式的多种形式。NVI手法自身是一个特殊形式的Template Method设计模式。将机能从成员函数移到class外部函数,带来一个缺点是,非成员函数无法访问class的non-public成员。tr1::funciton对象的行为就像一般函数指针。这样的对象可接纳"与给定...原创 2019-12-10 14:26:00 · 1342 阅读 · 0 评论 -
34. Differentiate between inheritance of interface and inheritance ofimplementations
区分接口继承和实现继承有如下继承体系:class Shape{public: virtual void draw() const = 0; // pure virtual function virtual void error(const std::string& msg); // impure virtual function int objectID() const;...原创 2019-12-06 15:52:44 · 1227 阅读 · 0 评论 -
33. Avoid Hiding inerited names
避免遮掩继承而来的名称请记住:derived classes内的名称会遮掩base classes内的名称。在public继承下从来没有人希望如此。为了让遮掩的名字在见天日,可使using声明式或转交函数。...原创 2019-12-06 13:14:20 · 1240 阅读 · 0 评论 -
32. Make Sure public inheritance models "is-a."
确定你的public继承塑模出is-a关系public inhritance(公开继承)意味着"is-a"(是一种)的关系。如果你令class D(“Derived”)以public形式继承class B(“Base”), 你便是告诉编译器,每一个类型为D的对象也是一个类型为B的对象,反之不成立。B是比D表现出更一般化的概念,而D比B表现出更特殊化的概念。请记住:"public继承...原创 2019-11-25 21:11:09 · 1306 阅读 · 0 评论 -
31. Minimize compilation dependencies between files
将文件键的编译依存关系降至最低如果使用object reference或object pointers可以完成任务,就不要使用objects。你可以只依靠一个类型声明式就定义出指向该类型的references和pointers;但如果定义某类型的objects。就需要用到该类型的定义式。尽量以class声明式替代class定义式。当你声明一个函数而它用到某个class时,并不需要该cla...原创 2019-11-25 13:04:37 · 1293 阅读 · 0 评论 -
30. Understand the ins and outs of lining
透彻了解inling的里里外外inline函数,看起来像函数,动作像函数,比宏好用得多,可以调用它们又不需要受函数调用所招致的额外开销。inline函数背后的整体观念是,将“对此函数的每一个调用"都以函数本体替代之。但是这样可能会增加你的目标码(object code)。过度热衷inlining会造成程序体积太大。inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻提出,也...原创 2019-11-13 17:51:21 · 1451 阅读 · 0 评论 -
28. Avoid returning "handles" to object internals
避免返回handles指向对象内部成员示例代码如下:class Point{public: Point(int x, int y); ... void SetX(int x); void SetY(int y); ...};struct RectData{ Point ulhc; Point lrhc;};class Rectangle{public:...原创 2019-11-09 16:40:40 · 1117 阅读 · 0 评论 -
27. Minimize casting
尽量少做转型旧式转型:(T)expression // C风格T(expression) // 函数风格新式转型:const_cast(expression)dynamic_cast(expression)reinterpret_cast(expression)static_cast(expression)const_cast通常被用来将对象的常量性转除(cast away...原创 2019-11-09 15:59:04 · 1275 阅读 · 0 评论 -
26. Postpone variable definitions as long as possible
尽可能延后变量定义式的出现时间有加密函数如下:std::string encryptPassword(const std::string& password){ ... std::string encrypted; if (password.size() < MinnumPasswordLenght) { throw logic_error("Password ...原创 2019-11-08 12:45:40 · 1454 阅读 · 0 评论 -
25. Consider support for a non-throwing swap
考虑写出一个不抛出异常的swap函数请记住:当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。如果你提供了一个member swap,也该提供一个non-member swap用来调用前者。对于class(而非templates),也请特化std::swap。调用swap时应针对std::swap使用using声明式,然后...原创 2019-11-08 11:33:53 · 1069 阅读 · 0 评论 -
24. Declear non-member functions when type conversions should apply to all parameters
若所有参数皆需类型转换,请为此采用non-member函数复数类如下:class Rational{public: Rational(int numerator =0, int denominator = 1); const Rational operator * (const Rational& rhs); int numerator() const; int den...原创 2019-10-28 13:14:09 · 1292 阅读 · 0 评论 -
23. Perfer non-member non-friend functions to member functions
宁以non-member、non-friend替代member函数请记住:宁可拿non-member non-friend函数替换member函数。这样做可以增加封装性、包裹弹性(packaging flexibility)和技能扩充性。...原创 2019-10-28 12:48:44 · 1432 阅读 · 0 评论 -
22. Declare data members private
将成员变量声明为private如果成员变量不是public,客户唯一能够访问对象的办法就是通过成员函数。使用成员函数可以让你对成员变量的处理有更精准的控制。将成员变量隐藏在函数接口的背后,可以为"所有可能的实现"提供弹性。某些东西的封装性与“与其内容改变时可能造成的代码破坏量”成反比。假如我们有一个public成员变量,而我们最终取消了它。多少代码可能会被破坏?所有...原创 2019-10-22 20:18:53 · 1399 阅读 · 0 评论 -
21. Don't try to return a reference when you must return an object
class Rational{public: Rational(int numerator = 0, int demoninator = 2); friend const Rational operator * (const Rational& lhs, const Rational& rhs); ...private: int n, d;}因为 oper...原创 2019-10-22 19:42:14 · 1415 阅读 · 0 评论 -
20. Prefer pass-by-reference-to-const to pass-by-value
宁以pass-by-reference-to-const替代pass-by-value有如下继承:class Person{public: Person(); virtual ~Person(); ...private: std::string name; std::string address;}class Student : public Person{pub...原创 2019-10-18 23:23:45 · 1386 阅读 · 0 评论 -
19. Treat class design as type design
设计class犹如设计type思考以下问题:新type的对象应该如何被创建和销毁?对象的初始化和对象的赋值该有什么样的差别?新type的对象如果被passed by value,意味着什么?什么是新type的“合法值”?你的新type需要配合某个继承图系吗?你的新type需要什么样的转换?什么样的操作符和函数对此新type而言是合理的?什么样的标准函数应该驳回?谁该取用新t...原创 2019-10-18 22:50:19 · 1247 阅读 · 0 评论 -
18. Make interfaces esay to use correctly and hard to use incorrectly
让接口容易被正确使用,不易被无用理想上,如果客户企图使用某个接口而却没有获得他所预期的行为,这个代码不该通过编译。如果代码通过了编译,它的作为就该是客户所想要的。预防客户错误的另外一个办法是,限制类型内什么事可做,什么事不可做。常见的限制是加const。除非有好理由,否则应该尽量令你的types的行为和内置types一致。任何接口如果要求客户必须记得做某些事情,就是有着“...原创 2019-10-18 22:42:56 · 1279 阅读 · 0 评论 -
17. Store newed objects in smart pointers in standalone statements
以独立语句将newed对象置于只能指针思考以下情形:int priority();void processWidget(std::shared_ptr<Widget> pw, int priority); 如果调用方式如下:processWidget(new Widget, priority());将会编译失败。因为processWidget需要一个std::sha...原创 2019-10-17 23:51:12 · 1242 阅读 · 0 评论 -
16. Use the same form in correspondng uses of new and delete
成对使用new和delete时采用相同形式int* pOne = new int;int* pArray = new int[10];...delete pOne;delete [] pArray;new一个int和一个int数据时,其内存结构可能如下:pArray所指向内存中还存在一个字段n来表示内存大小。delete pOne; 只会析构一个对象,它也只需要析构一个对象...原创 2019-10-17 13:05:29 · 1388 阅读 · 0 评论 -
15. Provide access to raw resources in resouce-managing classes
在资源管理类中提供对原始资源的访问资源管理类必须提供原始对象的访问接口,以便直接访问资源。智能指针std::shared_ptr就提供成员函数get()访问原始资源。有以下管理类:Font GetFont() { ... } // 获取Font全局函数ReleaseFont(Font ft) { ... } // 释放Font全局函数ChangeFontSize(Font ft)...原创 2019-10-17 12:39:54 · 1430 阅读 · 0 评论 -
14. Thinking carefullly about copying behavior in resource-managing classes
在资源管理类中小心copying行为原创 2019-10-15 12:42:29 · 1285 阅读 · 0 评论 -
13. Use Objects to manage resources.
以对象管理资源这里的资源指的主要是指堆内存。有一投资类:class Investment { .. };...Investment* CreateInvestment();考虑如下调用:void f(){ Investment* pInv = CreateInvestment(); ... delete pInv;}调用f()时,如果中途提前退出,或者出现异常导致...原创 2019-10-14 23:13:32 · 1361 阅读 · 0 评论 -
12. Copy all parts of an object
复制对象时勿忘其每一部分将copy构造函数和copy assignment函数统称为copying函数。如果自己声明了copying函数,编译器将不会再次声明。考虑以下代码:void LogCall(const std::stirng& funcName);class Customer {public: ... Customer(const Customer&...原创 2019-10-14 22:39:11 · 1442 阅读 · 0 评论 -
11.Handle assignment to self in operator =
在operator = 中处理“自我赋值”请记住:确保当对象自我赋值时operator = 有良好行为。其中技术包括比较“来元对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。确保任何函数如果操作一个以上的对象,而其中多个对象时同一个对象时, 其行为依然正确。...原创 2019-10-14 17:47:37 · 1443 阅读 · 0 评论 -
10. Have assignment operators return a reference to *this
令operator = 返回一个reference to *thisint x, y, z;x = y = z = 15;这是“连锁赋值”。对于自定义类,如果要满足连锁赋值,赋值操作符必须返回一个引用指向操作符的左侧实参。其他复合赋值操作符也一样。class Widget{public: ... Widget& operator = (const Widget&am...原创 2019-10-14 13:12:05 · 1372 阅读 · 0 评论 -
09. Never call virtual funcitons during construction or destruction
绝不在构造函数和析构函数过程中调用virtual函数请记住:在构造和析构期间不要调用virtual函数, 因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。...原创 2019-10-14 13:00:22 · 1144 阅读 · 0 评论 -
08.Prevent exceptions from leaving destructors
别让异常逃离析构函数请记住:析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常。析构函数应该捕获任何异常,然后吞下它们(不传播)或结束程序。如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非再析构函数中)执行改操作。...原创 2019-10-14 12:42:22 · 1112 阅读 · 0 评论