Effective C++
w0131
这个作者很懒,什么都没留下…
展开
-
链接时报错:undefined reference to vtable 原因以及解决办法
链接时报错:undefined reference to vtable 原因以及解决办法转载 2022-09-02 17:59:03 · 1827 阅读 · 2 评论 -
typedef
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar原创 2021-06-21 16:12:36 · 163 阅读 · 0 评论 -
条款37:绝不重新定义继承而来的缺省参数值
静态绑定:就是在调用之前,以及定义好。取决静态类型?动态绑定:调用一个虚函数时,究竟调用哪一份函数实现代码,取决于发出调用的那个对象的动态类型。静态类型:就是它在程序中被声明所采用的类型。动态类型:目前所指对象的类型。一个对象有静态类型和动态类型,两者并不冲突。class Shape{public: enum ShapeColor{ Red ,Green ,Blue}; virtual void draw (ShapeColor color = Red) c...翻译 2021-02-26 16:24:33 · 106 阅读 · 0 评论 -
条款36:绝不重新定义继承而来的non_virtual函数
class B {public: void mf(); ....};class D : public B{ ....};D x;----------B* pB =&x;pB->mf();--------D *pD =&x;pD->mf();两次调用都会调用指针类型对应的版本,而不是根据对象是哪种类型决定。1:非虚函数比如B::mf和D::mf都是静态绑定。意思是由于pB被声明一个指向B的指针,通...翻译 2021-02-26 11:39:21 · 99 阅读 · 0 评论 -
条款34:区分接口继承和实现继承
1.声明一个纯虚函数得目的是为了让子类只继承函数接口。2.声明一个虚函数得目的是让子类继承该函数得接口和缺省实现。3.声明非虚函数得目的是为了令子类继承函数的接口及一份强制性实现。...翻译 2021-02-25 16:04:42 · 62 阅读 · 0 评论 -
条款33:避免遮掩继承而来的名称
当位于一个子类成员函数内指涉父类内的某物时,编译器可以找出我们所指涉的东西,意味子类继承了声明于父类内的所有东西。实际运作方式是:子类的作用域被嵌套在父类的作用域中,但在子类找不到定义时,作用域替换为父类的作用域。class Base{private:int x;public: virtual void mf1() =0; virtual void mf1(int); virtual void mf2(); void mf3();...翻译 2021-02-25 15:20:44 · 56 阅读 · 0 评论 -
条款31:将文件间的编译依存关系降至最低
#include <string>#include "date.h"#include "address.h"class Person{std::string name() const;std::string birthDate() const;std::string address() const;}如果程序这样写的话,Person定义文件和其他含入文件之间形成了一种编译依存关系。如果这些头文件有任何一个被改变,或者这些头文件所依赖的其他头文件发生改变,那么每一个翻译 2021-02-25 11:00:34 · 109 阅读 · 0 评论 -
条款30:透切了解inlining的里里外外
inlining函数背后的整体观念就是将:对此函数的每一个调用,都以函数本体替换之。如果inline函数的本体很小,编译器针对“函数本体”所产生的代码可能比针对“函数调用”所产生的代码更小。inline只是对编译器的一个申请,而不是强制命令。这项申请可以隐形提出,也可以明确提出。在class类定义理的函数都是隐形inline申明。明确申明inline函数的做法则是在其定义式前加上关键字inline。对Virtual函数声明inline声明失败!因为virtual函数意味着“等待”,等到运翻译 2021-02-24 17:56:57 · 83 阅读 · 0 评论 -
条款29:为“异常安全”而努力是值得的
class PrettyMenu{ public: ... void changeBackground (std::istream & imgSrc); ... private: Mutex mutex; Image* bgImage; int ImageChanges;};void pret...翻译 2020-12-10 16:47:02 · 150 阅读 · 0 评论 -
条款28:避免返回handles指向对象内部成分
class Rectangle{ public: ... point & upperLeft()const { return pData->ulhc;} point & lowerRight() const { return pData->lrhc;} ...};这样的设计可通过编译,但却是错误的,实际上它是自我矛盾的。一方面upperLeft和lowerRight 被声明为const成员函数,...翻译 2020-12-10 14:00:19 · 107 阅读 · 0 评论 -
条款27:尽量少做转型动作
C++四种新式转型const_cast<T>(expression)通常用来将对象的常量性转除,将const转成non_const;dynamic_cast<T>(expression)用来执行“安全向下转型”通过父类访问子类reinterpret_cast<T>(expression)很少用到,忽略static_cast<T>(expression)用来强迫隐式转换,例如将non_const对象转为const对象,或将int转翻译 2020-12-10 11:30:33 · 73 阅读 · 0 评论 -
条款26:尽可能延后变量定义的出现时间
只要你定义了一个变量而其类型带有一个构造函数或析构函数,那么当程序的控制流到达这个变量定义时,你便得承受构造成本;当这个变量离开其作用域时,你便得承受析构成本。即使这个变量最终并未被使用,仍需耗费这些成本,所以你应该尽可能避免这种情形。std::string encryptPassword(const std:;string & password){ using namespace std; string encrypted;...翻译 2020-12-09 10:30:34 · 62 阅读 · 0 评论 -
printf()函数不能直接输出string 类型
因为string不是c语言的内置数据,所以直接printf输出string类型的是办不到的例如printf("%s\n",a.c_str());原创 2020-12-09 09:15:50 · 301 阅读 · 0 评论 -
条款25:考虑写出一个不抛出异常的swap函数
缺省情况下swap动作可由标准程序库提供的swap算法完成。namespace std{ template <typename T> void swap (T& a, T& b) { T temp(a); a=b; b= temp; }}但是使用默认额swap效率非常低,例如:class ...翻译 2020-11-05 16:08:20 · 99 阅读 · 0 评论 -
条款24:若所有参数皆需类型转换,请为此采用非成员函数
class Rational{ public: Rational (int numrator = 0, int denominator =1 ); //构造函数不为explicit 允许隐式转换。 int numerator() const ; //分子的访问函数 int denominator() const; //分母的访问函数 private: ...};如果你想支持运算诸如加法,乘法。class R...翻译 2020-11-05 13:27:42 · 61 阅读 · 0 评论 -
条款23:宁愿以非成员,非友元替换成员函数
class WebBrowser{ public: ... void clearCache(); void clearHistory(); void removeCookies(); ...};如果想执行类里面所有的动作,有点用户可能会提供这样的一个函数class WebBrowser{ public : ......翻译 2020-11-05 10:40:26 · 103 阅读 · 0 评论 -
条款22:将成员变量声明为private
假设我们有一个public成员变量,而我们最终取消了他,多少代码可能会被破坏?所有使用它的客服码都会被破坏,而那是一个不可知的大量。因此public成员变量完全没有封装性。假设我们有一个protected成员变量,而我们取消了他。有多少代码可能会被破坏?所有使用它的子类都会被破坏,那往往也是一个不可知的变量,因此protect和public 成员一样缺乏封装性。protected并不比public更具有封装性。...翻译 2020-11-05 09:26:28 · 59 阅读 · 0 评论 -
条款21:必须返回对象时,别妄想返回其reference
const Rational & operator* (const Rational & lhs, const Rational & rhs);{ Rational result (lhs.n * rhs.n , lhs.d * rhs.d); return result;}如果定义一个本地变量,就是在stack空间创建对象。问题是:这个函数返回一个reference指向result,但result是个local对象,而local对...翻译 2020-11-04 11:10:45 · 104 阅读 · 0 评论 -
条款20:宁愿以pass-by-reference-to-const(const &)替换pass-by-value(以值传递)
class Person{...}class Student : public Person{...}bool validateStudnt(Student s);Student plato;bool platoIsOk = validateStudent(plato);对此参数而言,参数的传递成本是“一次Student copy构造函数调用,加上一次Student析构函数调用”。Student对象内还有两个string对象,所以每次构造一个Student对象也翻译 2020-11-03 18:01:50 · 55 阅读 · 0 评论 -
条款18:让接口容易被正确使用,不易被误用
函数接口,class接口,模板template接口,每一种接口都是客户与你的代码互动的手段。class Data{ public: Date(int month,int day,int year); ....}以上代码可能会有两种错误!1,他们可能传递错误次序参数;Date d(30, 3, 1995);2,他们可能传递一个无效的月份或天数;Date d(2, 30, 1995);既然这样我们可以导入简单的外覆类型来区别天数,月份,和年份。s...翻译 2020-11-03 17:07:41 · 50 阅读 · 0 评论 -
条款17:以单独语句将new对象置于智能指针auto_ptr,tr1::shared_ptr
int priotity(); //获取优先权void processWidget(std::tr1::shared_ptr<Widget>pw,int priority);现在考虑调用processWidget:processWidget(new Widget, priority());不能通过编译,tr1::shared_ptr构造函数是一个explicit构造函数,无法进行隐式转换,将来自“newWidget”的原始指针转换为processWidget要求的tr1::s..翻译 2020-10-29 16:31:20 · 73 阅读 · 0 评论 -
条款16:成对使用new和delete时采取相同形式
std::string *stringPtr1 = new std::stirng ;std::stirng * stringPtr2 =new std::string [100];...delete stringPtr1; //删除一个对象delete [] stringPtr2; //删除一个由对象组成的数组当你对着一个指针使用delete,唯一能够让delete知道内存中是否存在一个“数组大小记录”的办法就...翻译 2020-10-29 15:31:28 · 82 阅读 · 0 评论 -
条款15:资源管理类提供对原始资源的访问
std::tr1::shared_prt<Investment>pInv(createInvestment());int daysheld(const Investment *pi); //返回投资天数你想这样调用他:int days =daysHeld(pInv); //错误因为daysHeld需要的是Investment *对象,你传给他的却是个类型为tr1::shared_ptr<Investment>对象。显...翻译 2020-10-29 11:32:30 · 63 阅读 · 0 评论 -
条款14:在资源管理类中小心coping行为
对于heap_based资源使用auto_ptr和tr1::shared_ptr。但是并非所有资源都是heap_based资源。对于这种资源auto_ptr和tr1::shared_ptr这样的指针不适合作为资源管理者,既然这样,需要建立自己的资源管理类。例如我们使用C API函数处理类型mutex的互斥器对象void lock(Mutex *pm);void nulock(Mutex *pm);为确保不会忘记一个被锁住的Mutex解锁,你可能希望建立一个class来管理机锁,这样的cl翻译 2020-10-29 10:36:31 · 274 阅读 · 0 评论 -
条款13:以对象管理资源
class Investment{...};Investment * createInvestment(); //一个工厂函数供应我们某个特定的Investment对象;void f(){ Investment * pInv =createInvestment(); ... delete pInv;}这看起来很妥当,但若干情况下"..."区域内的一个过早的return语句。如果这样一个return被执行起来,控制流就绝不会触及...翻译 2020-10-29 10:00:32 · 124 阅读 · 1 评论 -
条款11:在operator=中处理“自我赋值”
class Widget{Widget w;...}w=w;//自我赋值有时候自我赋值也不是这么容易能看出来的a[i]=a[j]; //i和j有相同的值,潜在的自我赋值*px=*py;//指向同一个东西,也是潜在的自我赋值有时自我赋值并不安全class BItmap{.....};class Widget{ ... private: Bitmap *pb;};Widget & Widget::operator=...翻译 2020-10-27 15:38:15 · 145 阅读 · 0 评论 -
条款10:令operator=返回一个reference to *this实现连续赋值
class Widget{ public: ... Widget & operator=(const Widget & rhs) //operator+=,operator=,operator-=,operator*= { ... return *this; } ...};翻译 2020-10-27 14:52:32 · 86 阅读 · 0 评论 -
条款09:绝不在构造和析构过程中调用virtual函数
class Transaction{ public: Transaction(); virtual void logTransaction()const =0; ...}Transaction::Transaction(){ ... logTransaction();}class BuyTransaction:public Transaction...翻译 2020-10-27 14:13:46 · 70 阅读 · 0 评论 -
条款08:别让异常逃离析构函数
class Widget{public:....~Widget(){....}};void doSomething(){std::vector<Widget> v;...}//v到这里被自动销毁假设v中含有十个Widgets,但在析构第一个元素时,有个异常抛出,当第二个Widget析构又抛出异常,这对C++而言太多了,在两个异常同时存在的情况下,程序不是结束执行就是导致不明确行为。理想情况下:class DBConn{public:翻译 2020-10-27 13:40:36 · 103 阅读 · 0 评论 -
条款07:为多态基类声明virtual析构函数
因为C++明确指出,当derived class对象经由一个base class指针被删除,而该base class带着一个non-vritual析构函数,其结果将未有定义---通常发生的是对象的derived成分没有被销毁。解决:给base class一个virtual析构函数。此后删除derived classs对象就会如你想要的那样,销毁整个对象,包括所有derived class成分:class TimeKeeper{public:TimeKeeper();virtual ~T翻译 2020-10-20 10:04:27 · 165 阅读 · 0 评论 -
条款06:若不想使用编译器自动生成的函数,就应该明确拒绝
如果你不声明copy构造函数或赋值构造函数,编译器可能为你产出一份,于是你的class支持复制和赋值。如果你声明它们,你的class还是支持赋值和复制。所以这里目标是要阻止copying!解决:所有编译器产出的函数都是public。为阻止这些函数被创建出来,你的自行声明它们,但这里没有要求你必须将它们声明为public。因此你可以将copy构造函数或赋值构造函数声明为private。声明为成员函数,成功阻止编译器创建默认版本,而令这些函数为private,使成功阻止人们调用它。并不是绝对安全,因为成翻译 2020-10-19 17:56:10 · 115 阅读 · 0 评论 -
条款04:确定对象被使用之前已先被初始化
最佳处理方法就是:永远在使用对象之前先将它初始化1.对于内置类型,你必须手工完成此事。int x=0;const char* text="a C-style string";2.至于内置类型以外的任何其他东西,初始化责任都落在构造函数身上。但是别混淆了赋值和初始化class PhoneNumber{....};class ABEntry{public:ABEntry(const std::string & name, const std::string &翻译 2020-10-19 17:20:04 · 181 阅读 · 0 评论 -
条款02:尽量以const,enum,inline替代#define
条款2:尽量以const,enum,inline替代#define1.const替代#define#define ASPECT_RATIO 1.65记号名称ASPECT_RATIO从未被编译器看见,所以在记号表可能看不到该记号,所以当你运用该常量发生一个编译错误时,可能会带来疑惑,因为该错误信息只会提到1.65而不是ASPECT_RATIO,如果该定义是在一个非你所写的头文件里,你肯定对1.65以及它来自何处没有概念,于是你将因为追踪它而浪费时间。解决:const double Asp.翻译 2020-10-19 15:23:04 · 80 阅读 · 0 评论