effective c++ 笔记 (6)

//---------------------------15/04/06----------------------------

//#18 让接口容易被正确使用,不易被误用

{

//  1:为了防止客户输入错误的参数,可以使用外覆类型来区别:

struct Day

{

explicit Day(int d): val(d) {}

int val;

};

struct Month

{

explicit Month(int m): val(m) {}

int val;

};

struct Year

{

explicit Year(int y): val(y) {}

int val;

};

class Date

{

public:

Date(const Month& m,
const Day& d, const Year& y);

...

};

//  这时,客户职能这么使用Date class:

Date d(Month(3), Day(30), Year(1995));

//  为了限制类型的值,比如一年只有12个月,Month应该反映这样的事实。

//  为了安全不直接使用enum,而是预先定义所有有效的Months:

class Month

{

public:

static Month Jan() {return Month(1);}

static Month Feb() {return Month(2);}

...

static Month Dec() {return Month(12);}

private:

explicit Month(int m);

};

Date d(Month::Mar(), Day(30), Year(1995));

/*  2:预防客户错误的另一个办法是:限制类型内什么事可做,什么事不能做。也就是加上const。

3:除非有好理由,否则应该尽量令你的types的行为与内置types一致

4:任何接口如果要求客户必须记得做某些事情,就是有着“不正确使用”的倾向。

较佳接口的设计原则是先发制人,比如条款13中,

令factory函数返回一个智能指针,可以避免客户忘记使用智能指针:                     */

std::tr1::shared_ptr<Investment> createInvestment();

//  5:tr1::shared_ptr支持定制型删除器,可以防范DLL问题:

std::tr1::shared_ptr<Investment> createInvestment()

{

std::tr1::shared_ptr<Investment> retval(static_cast<Investment*>(0),

getRidOfInvestment);

retval = ...;

return retval;

}

}

//#19   设计class犹如设计type

{

/*  1:新type的对象应该如何被创建和销毁?

这会影响到你的class的构造函数和析构函数,以及内存分配函数和释放函数。

当然前提是如果你打算撰写他们。

2:对象初始化和对象的赋值该有什么样的差别

这个答案决定了构造函数和赋值操作符的行为,以及差异。

3:新type的对象如果被passed by value,意味着什么?

copy构造函数用来定义一个type的pass by value该如何实现。

4:什么是新type的“合法值”

你的class必须维护自己的约束条件,也就决定了你的成员函数

(特别是构造函数、赋值操作符、和所谓的setter函数)必须进行错误检查工作。

5:你的新type需要配合某个继承图系吗?

继承既有的class会受到哪些class的设计的束缚,特别是他们的函数是virtual或non_virtual的影响

如果允许别人继承自己的类,就会影响你所声明的函数是否为virtual

6:你的新type需要什么样的转换

是否需要隐式转换、显式转换。

7:什么样的操作符和函数对此新type而言是合理的?

这个答案决定你为你的class声明哪些函数,其中某些该是member函数。

8:什么样的标准函数应该驳回

你不想要系统为你声明的函数要声明为private。

9:谁该取用新type的成员

这个答案决定了哪个成员为public,protected,private。以及哪个class或function应该是friend

10:什么是新type的“为声明接口”

它对效率、异常安全性以及资源运用提供何种保证

11:你的新type有多么一般化

看看自己是否应该定义一个新的class template

12:你真的需要一个新type吗

如果只是为既有的class添加机能,那么可能单纯定义一个或多个non member函数或templates

更能达到目标。

*/

}

//#20   宁以pass by reference to const替换pass by value

{

/*  1:pass by value 需要调用copy构造函数产出一个副本,这可能使得pass by value

成为昂贵的操作。如果传递的是一个自定义class,通常需要调用一次copy构造函数
加 一次析构函数

如果这个class继承自别的类,又需要多调用好几次这两个函数。

2:by reference方式传递参数可以避免slicing(对象切割)问题:

一个derived class
对象以by value方式传递并被视为一个base class对象时,base class

的copy构造函数被调用,而“造成此对象的行为属于derived class
对象”的部分被切掉了,只留

下了一个base class对象。这绝不是你想要的。

3:reference通常以指针来实现出来,所以pass by reference就相当于传递指针。因此如果是一些

内置类型对象(比如int) pass by value
往往比 pass by reference的效率高些。

4:除了内置类型
和 stl的迭代器和函数对象,其他的对象都以pass by reference to const

替换 pass by value。

*/

}

//#21   必须返回对象时,别妄想返回其reference

{

//  1:一些值必须返回pass by value:

//      1>通过在stack上创建对象并返回这个对象的引用:

const Rantional& operator* (const Rantional& lhs,
const Rantional& rhs)

{

Rantional result(lhs.n * rhs.n, lhs.d * rhs.d);

return result;

}

/*      这里有两个点:

1)这样也调用构造了,效率并没提高。

2)返回了一个已经被销毁的对象。严重的错误!

2>通过在堆上创建对象并返回这个对象的引用:

*/

const Rantional& operator*(const Rantional& lhs,
const Rantional& rhs)

{

Rantional result =
new Rantional(lhs.n * rhs.n, lhs.d * rhs.d);

return result;

}

//      这样的话,谁负责delete?而且还是需要一次构造函数。

//      3>使用static对象:

const Rantional& operator* (const Rantional& lhs,
const Rantional& rhs)

{

static Rantional result;

result = ...;

return result;

}

//      这样首先线程不安全,其次使用if((a * b) == (c * d))总是返回true;

//  2:当一个函数必须返回新对象时,就让那个函数返回一个新对象呗!

inline const Rantional
operator* (const Rantional& lhs,
const Rantional& rhs)

{

return Rantional(lhs.n * rhs.n, lhs.d * rhs.d);

}

}

//#22   将成员变量声明为private

{

/*  1:首先看看成员变量不该是public:

1>一致性:如果没有public成员变量,客户唯一能访问对象的办法就是使用成员函数

客户就不需要在访问成员时疑惑地试着记住是否使用小括号。

2>可以更加精准地控制成员变量:你可以通过函数控制成员变量的读写。

3>封装性:如果通过函数访问成员变量,日后就算更改了这个变量的计算方法,或者直接更改了变量,

客户也不知道,也不必知道。

不封装就意味着不改变。

2:成员变量不该是protected:

道理和public第三点一样,这样对derived class并没有封装性可言

}

时间: 2024-10-18 12:22:26

effective c++ 笔记 (6)的相关文章

Effective C++笔记:构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构

Effective C++笔记06:继承与面向对象设计

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

Effective c++(笔记)之继承关系与面向对象设计

1.公有继承(public inheritance) 意味着"是一种"(isa)的关系 解析:一定要深刻理解这句话的含义,不要认为这大家都知道,本来我也这样认为,当我看完这章后,就不这样认为了. 公有继承可以这样理解,如果令class D以public 的形式继承了class B ,那么可以这样认为,每一个类型为D的对象同时也可以认为是类型为B的对象,但反过来是不成立的,对象D是更特殊化更具体的的概念,而B是更一般化的概念,每一件事情只要能够施行于基类对象身上,就一定可以应用于派生类对

Effective c++(笔记) 之 类与函数的设计声明中常遇到的问题

1.当我们开始去敲代码的时候,想过这个问题么?怎么去设计一个类? 或者对于程序员来说,写代码真的就如同搬砖一样,每天都干的事情,但是我们是否曾想过,在c++的代码中怎么样去设计一个类?我觉得这个问题可比我们"搬砖"重要的多,大家说不是么? 这个答案在本博客中会细细道来,当我们设计一个类时,其实会出现很多问题,例如:我们是否应该在类中编写copy constructor 和assignment运算符(这个上篇博客中已说明),另外,我们是让编写的函数成为类的成员函数还是友元还是非成员函数,

Effective C++笔记05:实现

条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止. 这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为. 遇到循环怎么办?此时往往我

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

Effective c++(笔记)----类与函数之实现

上篇博客中集中说明了在设计一个类的时候常遇到的问题,当然博客中还夹杂着我随时想到的一些知识,发现自己写博客没很多人写的好,可能是自己语言不会组织,要么就是写的东西大家不愿意看,反正是有这方面的专业问题或者博客中有什么明显的错误和问题,大家提出来,我也好改进哈! 回归正题,这篇博客就大概的把Effective c++中类与函数这节看到的知识点做个笔记. 设计好一个类后,自己就要去实现这个类(实现类中的成员函数.友元.非成员函数等) 可能大家会遇到以下问题 1.在类的成员函数中,尽量避免返回内部数据

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

java effective 读书笔记

java effective 读书笔记 [1]创建和销毁对象 1 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 2 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 3 枚举 singleton 不知道怎么操作,觉得意义不大 单例模式 4 私有化构造器不能实例化,也不可被子类继承 5 能用原生类的就尽量不用对象 [2]对于所有对象都通用的方法 reflexivity 自反性 symmetry 对称性 [3]类成员 降低可访问性 尽量把公有域 变成私有域,并提供

Effective c++(笔记) 之 杂项讨论

看到了Effective c++的最后一章,最开始的那章---内存管理还没搞清楚,准备那章搞清楚完也写篇博客,不管怎样,有好的开始就应该让它有个完美的结束,杂项讨论这章是作者将那些分到哪章都不合适的就索性放到了最后讨论,我看完后从中摘出自己认为重要的坐下笔记,如果能帮得到大家,那就更荣幸了哈! 1.当我们定义一个类时,编译器会自动给我产生哪些成员函数? 解析:我们都知道,当我们定义类时,如果我们没有定义某些成员函数的话,编译器会总会给我们自动合成,这就是编译器默默为我们完成和调用函数,这些函数主