Effective C++ 读书笔记(1828):类与函数之设计和声明

类与函数的设计和声明

看看作者思考问题的角度:

对象如何产生和销毁: 构造析构、new和delete的重载

对象的初始化和赋值:构造、拷贝构造、赋值重载

新型别转换相关:合法值的规范检验、继承体系、是否隐式转换

访问权限:public、protected、private如何设计

 

Item18 -- 努力让接口完满且最小化

1,KISS原则;2,头文件的重要性;

 

Item19 -- 区分member functions, non-member functions和friend functions三者

1,如果要实现虚函数,必须是member function
2,让operator<<和operator>>成为non-members,如果还需要获取类的非公共成员变量,声明为friend。原因,如果是func为member,那么以后书写顺序应该是obj>>cin,obj<<cout,这样不符合习惯
3,只有non-member才能在最左参数身上实施型别转换。如果需要对函数f的最左侧参数进行型别转换,那么f为non-function,如果还需要获取类的非公共成员变量,声明为frind。
举例,operator *(Class &lhs, Class &rhs)这种声明,2*obj2的调用,需要对2进行型别转换(构造函数声明为explicit可以阻止隐式型别转换),这样就必须为non-member

Item20 -- 避免将data members放在公开接口中

Effective中举了三个原因,说明为什么不要放在公开接口中

  1. 一致性,以后对类对象的所有操作,均需要带(),也就是只能调用函数,不能获取变量
  2. 获取控制性,比如只读、可读可写、不处理,通过不同的函数实现
  3. 函数抽象性,提供一个借口,底层如何实现上层用户不用关心

不过在实际编程中,很少人能够完全做到这点,毕竟需要自己花些时间来写get和set,暂时我也没找到自动生成get、set函数的方法,所以鱼与熊掌不可兼得,若想获得好处,就得费力写get、set了。

Item21 -- 尽可能使用const

1,*号在中间,前定内容后定针
2,返回值用const修饰,说明返回值是只读的,不能修改
3,函数后面用const修饰,说明该函数不能修改任何变量。函数可以据此进行重载,有const的函数被const对象调用,没有const的函数被非const对象调用
const的真正意义是什么?不变性,具体的体现有两种说法:A, bitwise. B, conceptual,A说法对位进行比较,如果没有修改则认为是不变的。B从概念层面进行判断,即使底层有修改,但对上层概念来讲是不变的,那就是不变的。但是C++语言只支持A,所以为了应付B,引入mutable修饰词,用来修饰上层概念不变,但是底层要修改的底层变量。
4,const可以通过const_cast取消常量性

Item22 -- 尽量使用pass-by-reference,少用pass-by-value

  1. C语言里面都是传值
  2. 传值成本比较大,会调用对象的拷贝构造,如果类比较复杂,则会创建和析构更多的对象
  3. 传引用会避免切割问题。Func(base&) 和Func(base)两种函数声明,内部调用f()虚函数,如果传递个derived对象,则传引用会调用derived.f(),而传值则会切割而调用base.f()

Item23 -- 当你必须回传object时,不要尝试传回reference

用重载乘法举例

Inline const Rational Operator*( const Rational& lhs, const Rational & rhs)

{

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

}

传回的是value,如果传回reference的话,内部变量析构之后,引用没有真正的对象

Item24 -- 在函数重载和参数缺省化之间,谨慎选择

void g(int x=0);

g();

g(10);

void f(); void f(int x);

f();

f(10);

两种方式要谨慎选择,避免出现模棱两可的情况

Item25 -- 避免对指针型别和数值型别进行重载

void f(int x);

void f(string *ps);

f(0)

0的存在会对指针和数值造成模棱两可,所以要坚决避免针对指针和数值进行重载

Item26 -- 防卫潜伏的ambiguity(模棱两可)状态

C++有一个哲学信仰,它相信潜在的模棱两可状态不是一种错误,但是对程序员来讲,将所有问题放到运行后发现就是一种灾难。所以程序员应该避免模棱两可。
类的转换,一是拷贝构造方式可以隐式转换,一是operator Class()方式,当需要型别转换时,就会有模棱两可

  1. 语言标准转换,6.02可以转换成int也可以转换成char
  2. 多继承也是如此

当遇到模棱两可情况时,程序员应该显式的说明采用哪种方式。

Item27 -- 如果不想使用编译器暗自产生的member functions,就应该明白拒绝它

  1. 使用private修饰防止公开调用
  2. 不定义防止friend等调用

private:

Array& operator=(const Array &rhs);(注意这里;表示不定义)

 

Item28 -- 尝试切割global namespace

namespace name1{

}

using namespace name1;

最好每个人都以自己姓名为name,进行分割,这样可以类似Java中的包的概念

原文地址:https://www.cnblogs.com/liuchen/p/1585666.html