自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(31)
  • 收藏
  • 关注

原创 《Effective C++》条款 35:考虑virtual函数以外的其他选择

文章目录Non-Virtual Interface 方式函数指针实现的Strategy模式由tr1::function完成的Strategy模式古典的Strategy模式当我们设计面向对象程序时,我们不一定仅是聚焦于virtual函数,其实我们可以有很多的替代方案,每种方式有自己特点和优势。加入游戏中的人物需要一个函数用以表现任务的健康状态(血量),而游戏中又具有各种不同的角色,因此,我们应该设计一个基类来表示任务角色的相同特征。相应的,该函数会有一个默认的实现方式。默认方式省略。事实上,在设计模

2021-03-31 16:27:57 209

原创 《Effective C++》条款34:区分接口继承和实现继承

继承关系中,由虚函数,纯虚函数、以及非虚函数的继承方式,这三种继承方式各自由各自的特点,一般三种成员函数大概目的可以分为以下:纯虚函数一般来说用于继承接口,而且是不可缺少的接口非纯的虚函数一般用于继承一个接口,以及一份缺省的实现,该实现可以被重载非虚函数一般是让派生类继承一个接口,以及一份不可更改的实现。非纯虚函数继承中的弊端以及避免方式一个表示飞机以及飞机飞行方式的类以及他的派生类之间的继承关系。上述的两种飞机A和B都选择默认的飞行方式,这时,只需要直接调用基类的飞行方式即可。倘若这时有

2021-03-30 17:09:38 121

原创 《Effective C++》条款33、避免遮掩而来的名字

对于继承关系中得函数得同名作用域问题,现在已经清楚编译器是如何去对作用域进行查找的了,但是我们依然需要了解在继承和虚函数的关系中,我们的同名e问题是怎样的。参考下面一段代码:上面的继承关系中,派生类和基类中的函数出现了同名的问题,这时,派生类中的同名函数将会遮掩掉所有基类中的同名函数。如下的用法将会更加清晰:即使派生类中的函数和基类中的有所不同,但是在派生类对象中,也无法调用基类中的同名函数。使用using避免同名函数遮掩问题我们可以使用using声名将派生类中的同名函数引入到派生类中,这样便

2021-03-30 15:25:26 115

原创 《Effective C++》条款 30、降低文件间的编译依存关系

文章目录handle classInterface class对于这样一个程序:上述的Person类中含有两个类的对象,因此该文件中应该包含相应的头文件,这就带来一个问题,当我们改变任何一个头文件,或者改变该头文件包含的任何头文件,那么Person类就会被重新编译,并且所有包含Person类的头文件也都将会被重新编译。也就是当一个头文件被修改时,不管是直接包含该头文件还是间接包含该头文件的文件都将重新编译,因此对于那些大型项目来说,这将会导致每次修改后的编译时间都将会大量增加。因此,我们期望再Pers

2021-03-29 17:21:36 198

原创 《Effective C++》条款29、保证异常安全

异常安全的要求程序的设计应该满足异常安全,而异常安全应该保证当异常发生时我们的程序应该处于一个合法的状态,这种合法的状态的状态有两个基本要求:不能泄露任何资源不允许数据败坏那么这两点要求具体参考如下代码:代码要求更改背景图片,但是该操作要保证原子性,因此,先对这个该操作进行上锁,操作完成后释放锁。先将原来的图片删除,然后再更改为新的图像。但是这会有个严重的问题,那就是当new运算符分配空间失败时这个程序实际上就不能保证异常安全,当发生异常,我们的互斥锁将会永远的锁上没无法释放,这就导致资源泄

2021-03-29 11:32:20 202

原创 《Effective C++》条款28 避免返回指向对象内部的对象或者引用

假设有一个类表示矩形,但是我们又不希望我们的类过于庞大,因此,我们将会定义一个表示点的类来表示某个点,而我们的矩形类中我们只需要保存相应的指针即可。我们在举行的类中设计两个表示举行的范围的函数,分别返回矩形的左上角和右上角。然而这样的设计本身就是一个矛盾体,因为当我们返回了point的引用我们将会改变矩形的参数,而const函数只是保证不在函数的内部不改变函数的成员,但是其返回的成员是一个点的引用,这样我们将会改变原来的矩形的参数。如我们返回的是const的引用,及如下:这样的话用户可用读取

2021-03-28 17:22:14 134

原创 《Effective C++》条款27、尽量的少做类型转换

C++程序的设计原则是尽可能的尽可能的避免的类型的转换,因为有时类型转换往往会带来一些编译上的错误,而有些虽然不会带来错误单数会导致逻辑上的错误,但是却很难发现。C++语言中提供了四种类型转换方式:...

2021-03-28 16:06:36 158

原创 《Effective C++》条款 26、尽可能延后变量的定义

变量定义原则当我们定义了一个变量时,特别是当这个变量需要构造和析构时我们需要承担这个变量的析构和构造成本,因此,我们定义变量的原则是当我们要使用该变量是我们才定义它。特别是抛出异常的程序中当我们定义变量时我们就需要考虑该异常是否一定会被用到,如下的程序:变量encrypted不一定会被用到,因为一旦发生异常,很有可能程序将会结束该函数的调用或者终止程序,所以正确的做法是将变量定义再异常抛出代码段的后面。如下的操作:使用拷贝构造函数我们定义变量有时我们需要将变量的值进行特定的初始化,如果用如下方式

2021-03-15 14:53:00 126

原创 《Effect C++》条款25、一个不抛出异常的swap函数

swap函数是一个常用的函数,在STL中有一个swap的基本版本,但是这个函数仅是采用简单的交换技术,效率实际上对于很多的情况是很低的。标准函数库的swap函数如下:非模板特化但是对于某些情况我们只需要交换某个指针,并不需要交换整个对象,因此此时我们调用标准库的函数的效率就会很低,因此对于某种特殊的对象的交换,我们需要写出自己的swap版本。比如下的类,我们只要交换它内部的指针便好。有一个Widget类包含PImpl的指针,我们希望有一个特化的版本能够针对特定的类,当调用swap时编译器就会调

2021-03-13 11:40:01 117

原创 构造函数不匹配问题 no matching function for call to ‘xxxx::xxxx(xxxx*)’

这个问题是一个有点难发现的问题,因为这行代码的:shared_ptr<VisualMachine>temp = make_shared<VisualMachine>(new VisualMachine);报错确实这样的:上述说我们的构造函数找不到何时的版本,编译器想要一个传递VisualMachine *的参数,为什么会这样报错呢?因为我们用错了make_shared<>函数。原本make_shared<>功能和new的功能极为相似,都是再堆上动态

2021-03-12 19:48:54 6537

原创 《Effective C++》条款 23、24尽可能使用非友元的非成员函数

23 、尽量使用非成员函数有一个浏览器用于表示网页浏览器,里面有众多的函数用于清理浏览器相关的东西。当然这一特性也可以由一个人非成员函数来提供:上述两种方式我们该选择那种方式呢?我们知道对于封装性而言,非成员函数非友元函数的封装性远高于友元函数和成员函数,因此,我们应该首先选择将函数声明为非成员非友元函数。而对于C++语言而言,上述的这种函数往往会和相应的类定义在同一命名空间中,这样我们能够在其他的文件中添加该类函数到相应的命名空间中。条款24 、如果多个参数需要隐式类型转换,将函数设计为非成员函

2021-03-12 10:49:51 154

原创 《Effective C++ 》条款21、22

条款21、函数必须返回对象时,不可返回引用因为前面讲过,函数参数传值方式的效率没有传引用的方式效率高,因此,我们便会萌生,函数的返回值是否也是如此。然而,并不是这样的,当我们用引用返回函数的值时,有时会导致致命的错误。考虑下面一个表现有理数的类:这个类的 operator* 函数是返回的是以值得方式进行传递的对象,倘若我们将这个函数改为以引用的方式进行传值。则我们必须为返回的引用建立相应的对象。建立对象的方式不外乎两种方式,一种创建是在stack空间里面,而另一种则是创建于heap上。倘若我们

2021-03-11 10:14:52 214

原创 《Effective C++》条款20、尽量用const &替换值传递

const &能避免拷贝的开销在c++的参数传递过程中,有两种传值方式,一种是我们将会传递值,另一种则是我们将会传递一个const 参数引用。这两种方式有本质的区别,我们更推荐传递常量引用的方式进行参数传递。考虑从以下代码:现在我们有个函数会把Student作为参数传入没然后判断该学生信息是否合法。如果我们采用以上的方式进行值传递,那么我们在函数的局部作用域内就会为我们传入的Student对象做一个值得拷贝,也就是调用Student的拷贝构造函数对其进行拷贝,然后离开函数的局部作用域后将

2021-03-10 10:53:12 212

原创 《Effective C++》条款18、19 接口和类的设计

18、接口设计接口的设计不应该被误用假如设计一个表示日期的类,如果我们如下设计那么当用户使用这种接口的时候很容易出现问题,有可能会将年和月的如期写反,也有可能会填写不符合常理的日期,因此这种接口的设计并不是很好。所以,为了防止用户把参数的顺序填写错误,我们可以将年月日封装成类,这样当用户填写错误顺序时就将会收到编译器的抱怨。但是其实上述的方法依然存在问题,那就是当我们不小心将月份输错,很有可能输出错误的月份,因此应该做进一步的封装,以防止用户输入错误的月份。我们将所有的月份信息预先封装到类

2021-03-09 16:36:38 94

原创 《Effective C++》条款16、17 new和delete的使用

条款16、new和delete成对的使用对于delete和new的使用我们一定要小心我们使用的版本,当我们new出的是单个对象时,我们的delete使用的相应版本应该是delete,而当我们new了一个数组时我们应该调用的是 delete[ ]来释放内存,也就是说我们使用的new和delete应该配对,否则将会发生未定义错误,因此,当我们new时出现了[ ]运算符,我们的使用的delete也应该出现[ ]运算符。但是有时即使我们记住了这个准则我们还是不能避免错误,如下代码:当我们用typedef将数

2021-03-09 10:01:02 170

原创 《Effective C++》条款15、资源管理类提供原始资源的访问

显示转换在我们的资源管理类中,有时我们需要使用到我们的原始类,所以我们需要在资源管理类中提供对原始资源的访问接口,在智能指针中,都提供了一个get()函数,这个函数使得我们能够获得智能指针内部封装的原始指针,同时智能指针也重载了*运算符和->运算符使得我们可以访问内部指针指向的资源。如果我们在我们自己的资源管理类中也同样的封装了一个原始类,同样的,我们需要提供我们的原始资源,对于一个字体的管理类。我们同样可以提供一个get()函数返回我们的原始资源。如果想要获得FontHandle类型的 f

2021-03-08 16:47:09 162

原创 《Effective C++ 》条款13、14 资源管理类(智能指针)

条款13、资源管理类当我们向系统申请资源时,我们总是需要在用完后归还,但是有时候我们总会忘记,即使我们不会忘记,但是由于异常或代码的维护都有可能导致我们的程序发生异常。void f(){ Object *obj=new Object(); ......... ......... delete obj;}假如上述程序发生错误,那么最后的delete操作将不会执行,所以我们不能总是依赖于delete操作帮我们去完成最后的内存释放操作,标准程序库中的智能指针可以帮我们完成这样的操作。auto

2021-03-08 10:41:16 128

原创 《Effective C++》条款12、继承中的拷贝和赋值

实现拷贝构造函数和赋值运算符时,我们不能遗忘任何一个成员,当我们自定义以上成员时,如果我们没有将其中的某个成员进行复制,编译器是没法检测出来的。这种情况下我们就会得到不正确的对象。所以当我们为某个类添加任何成员时,我们必须记得修改我们的拷贝构造函和复制运算符重载。派生类的拷贝和赋值在派生类中实现拷贝构造函数和复制运算符时我们不能遗忘基类成分,我们必须考虑我们派生类中的隐藏的基类成员的赋值。考虑以下的案例:class A {public: A() : Num(0), Name("") {}

2021-03-07 11:24:12 154

原创 《Effective C++》条款10、11(赋值返回和自赋值问题)

条款10、operator = 返回一个 *this的引用因为赋值我们有时会把它写成连锁的形式,因此我们的赋值运算符重载时应该能够处理这种情况。以上赋值将会被解析为如下格式:所以为满足以上的情形,赋值运算应该返回一个自己的引用,即返回 *this即可。11 赋值运算中处理自赋值赋值运算中,往往会有自赋值的出现,而往往自赋值会发生在很隐晦,因为指针和引用的使用,很可能出现自赋值这种情况的发生。所以在我们所编写的代码应该能够处理这种情况。如下代码:如果上述中赋值的对象是相同的,那么就会导

2021-03-06 10:54:36 171

原创 《EffectiveC++》条款09 析构和构造时不调用虚函数

在多态操作中,我们不能在析构函数和构造函数中调用虚函数,因为在基类构造和析构期间,我们不能调用派生类的函数,也就是说,构造和析构期间的虚函数不在是虚函数。考虑以下代码:上述代码我们想要在构造基类的时候调用派生类logTransaction(),但是这并不会实现,实际将会调用基类的函数,这种情况下实际派生类的logTransaction()还未初始化,因为编译器总是会在派生类之前初始基类成员,因此编译器没办法找到基类的函数调用,所以只能调用父类的函数,而父类的函数为纯虚函数,因而编译器将会发生连接错误。

2021-03-05 16:37:27 181

原创 《Effective C++》条款 07、08(多态下的虚析构函数,析构函数和异常)

07虚析构函数C++中明确的定义了,当一个派生类对象经由一个base class指针删除,而该base class 带有一个非虚函数的虚构函数,其结果是未定义的。实际上这种情况下,将会调用基类的析构函数,因而,派生类独有的对象将会没有释放内存,因此编译器将会报错。因此在涉及多态的操作中,无疑我们的析构函数应该设计为虚函数,同时只要一个类中有任何一个虚函数,那么我们的类都用改设计为虚函数。但是如果一个类中没有虚函数,那么这个类一般是不会用作为基类的,那么这时候我们就应该将该函数的析构函数设计为虚函数,因

2021-03-05 15:30:31 163 1

原创 《Effective C++》条款05、06(编译器自动生成的函数)

05 编译器自动合成的函数一般情况下,如果我们的类没有自定义的构造函数、拷贝构造函数、以及复制运算符重载,那么编译器就会为我们自动合成一个这些函数。因此当你写一个空类时,其实你的代码实际上是包含这些函数的,但是编译器将他隐藏了。当你需要用到这些函数时,编译器就会合成这些函数。含有引用 &和const成员变量会阻止合成赋值和拷贝在C++语言中,对于某个变量的引用,一旦我们确定了某个变量引用了某个对象,则这个引用将不能在指向其它对象。而对于const属性的成员,我们将不能对其赋值和修改,因此

2021-03-05 09:55:40 1132 5

原创 《Effective C++》条款04(确定对象被使用前已初始化)

在c++中对象在使用前应该初始化,对于初始化有两种一种是利用初始化列表初始化,另一种则是采用赋值的方式进行初始化,但是因为用列表初始化的效率会比用赋值符号初始化高效,所以,C++语言中建议用列表初始化完成对象的初始化。当用构造函数完成数据初始化时,应该确保每一个成员变量被初始化。如下的赋值方式:以上的方式不值得推崇,而使用成员列表初始化具有更高的效率,因为对于大多数的类型成员来说,先调用默认构造函数在调用赋值运算符的方式比单一的copy要低效。因此我们可以这样构造。对于没有用参数的构造函数,我们可

2021-03-05 09:05:12 135 1

原创 《Effective C++》条款03(尽可能的使用const)

条款03 尽可能的使用constconst出现形式const关键字形式多种多样,对于普通变量的使用其规则就很多,如下图所示:const关键字总结:const关键字出现在“ * ”号左边,表示被指对象为常量,如果const出现在“ * ”右边,表示指针自身为常量;如果const关键字即出现在“ * ”左边又出现在“ * ”右边,那么指针和被指对象都是常量。如下表示的指针情况相同:STL中的常量迭代器和指向常量的迭代器形如指针和const结合一样,迭代器也有两种版本,分别是指向常量的迭代器和常量

2021-03-04 11:08:32 195 1

原创 《Effective C++》条款01、02(以const,enume,inline,替换#define)

1.条款01:视C++语言为一个联邦C++语言的四大部分主要如下图所示:这也是对问题C语言和C++语言有什么不同? 的最佳回答之一。条款02:尽量以const,enume,inline,替换#define如下的一个定义:#define RATIO 1.6352对于预编译的的变量,并不会进入到符号表中,当程序报错时可能对反馈数据1.6352出错,而不是RATIO变量。所以C++语言中用以下语句代替。const double Ratio = 1.6352;作为常量,Ratio将会进入符号

2021-03-03 15:27:50 1124 2

原创 C++学习笔记----extern “C”

C++语言中引入其他语言,不如用C++语言调用C语言的库函数,则需要用```extern "C"关键字来进行声名。链接指示与头文件指向extern "C"的函数指针C++函数指针和extern “C”函数指针不能相互转换。链接指示对整个声名都有效可以将C++语言导入到其他语言中使用注意命名的冲突...

2021-03-03 10:43:54 136

原创 C++学习笔记----位域和volatile限定符

1.位域位域一搬用于向其他程序或者硬件设备传递二进制数据,位于载内存中的布局一般和机器相关的。位于类型一般必须是整型或者枚举类型,位域的声名形式是在成员名字之后紧跟一个冒号以及一个常量表达式,该表达式指定所占的二进制位;取地址符不能作用域位域,任何指针都无法指向位域。使用位域使用位域之前先熟悉以下C语言中的位运算符相关的知识;位域的访问方式与访问类的其他数据成员的方式非常相似:通常将位操作运算符运用于位域的操作:2.volatile限定符volatile主要运用于和机器相关的变量,当一个

2021-03-03 10:30:59 234

原创 C++学习笔记----union

union和和C语言中的union差不多相同,只是在c++中被设计成为了类。要点如下:union不能含有引用类型的成员可以指定public、private、protected、默认为publicunion Token{ int a; double b; char c;};union初始化和使用Token t={'a'};//初始化c成员Token t1={5.0};//初始化b成员t.c='d';含有类类型成员的union以及union判别式当union中含有类类型的成员时

2021-03-02 18:36:21 1298

原创 C++学习笔记----嵌套类

定义在另一个类的内部的类被称为嵌套类,嵌套类和外层类之间的成员名不能冲突。嵌套类的名字仅在外层类作用域中可见,其他作用域不可见。嵌套类符合public、private、protected的访问规则。嵌套类的声明class A{public: class B;//后续定义,先声明后使用 void print() { cout<<"hello c++"<<endl; }}//嵌套类的定义class A::B{public: void show() {

2021-03-02 15:15:09 154

原创 C++学习笔记----类成员指针

1.类成员变量指针成员指针的用法我们通常用的指针,一般指向类的对象,其实我们也可以定义类的数据成员的指针,数据成员的指针可以简单的看成是类成员的一个别名,说如果是非const的指针则可以修改其绑定的对象的值。成员指针使用案例:class test{public: friend void MePointer(); test() = default; test(string name):Name(name){}private: string Name;};v

2021-03-01 15:52:38 848

原创 C++学习笔记----dynamic_cast、typeid

dynamic_cast主要用于基类和派生类的转换,我们可以将一个派生类转换称为基类的对象。有两种方式进行转换,一种是传递指针,另一种则是传递引用。转换的基类和派生类中应该含有虚函数。1.派生类向基类的转换指针类型的dynamic_castclass Base{public: Base() = default; Base(string name):B_Name(name){ } virtual void print() { co

2021-03-01 10:17:43 350

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除