Efftive C++ notes
1.公有继承意味着是“是一个”,对于基类的任何都适合,然而这是一种理想话,比如说鸟会飞,但企鹅不会飞啊。2.纯虚函数:具体类中重新声明,抽象类中往往没有定义。这样做的目的,使子类仅仅继承父类的接口(而没有继承其接口的实现)
注:为纯虚函数提供定义也是有可能的,也就是可以为纯虚函数提供实现,但调用它的唯一方法是通过类名完整地指明是哪个调用。即Shpe * ps1 = new Rectangle; ps1->Shape::draw();
3.简单虚函数(非纯),使派生类继承函数的接口和缺省实现。
这样做很危险。竟然试图让ModelC对象如同ModelA或ModelB那样飞行。这种行为可不能换来旅客对你的信任!
窍门在于切断虚函数的接口和它的缺省实现之间的联系
--纯虚函数必须在子类中重新声明,但它还是可以在基类中有自己的实现
4.非虚函数的目的在于,使派生类继承函数的接口和强制性实现,表示一种特殊性上的不变性,所以它决不能在子类中重新定义
5.事实上是:几乎任何一个作为基类使用的类都有虚函数
6.如果写类D时重新定义了从类B继承而来的非虚函数mf,D的对象就可能表现出精神易做图症般的异常行为。也就是说,D的对象在mf被调用时,行为有可能象B,也有可能象D,决定因素和对象本身没有一点关系,而是取决于指向它的指针所声明的类型。引用也会和指针一样表现出这样的异常行为
7.虚函数是动态绑定而缺省参数值是静态绑定的
8.对象的动态类型是由它当前所指的对象的类型决定的。即,对象的动态类型表示它将执行何种行为。
9.决不要重新定义继承而来的缺省参数值,虚函数是动态绑定的,但缺省参数是静态绑定的。这意味着你最终可能调用的是一个定义在派生类,但使用了基类中的缺省参数值的虚函数:
10.对于一个虚函数,编译器可以根据所使用对象的类型来保证正确的函数调用
11.“有一个”、“用...来实现”
12.类型T影响类的行为吗?如果T不影响行为,你可以使用模板。如果T影响行为,你就需要虚函数,从而要使用继承。
13.· 当对象的类型不影响类中函数的行为时,就要使用模板来生成这样一组类。
· 当对象的类型影响类中函数的行为时,就要使用继承来得到这样一组类。
真正消化了以上两点的含义,你就可以在设计中游刃于继承或模板之间。
14.如果两个类之间的继承关系为私有,编译器一般不会将派生类对象(如Student)转换成基类对象(如Person)。
Student类从Person类公有继承,为了使某个函数成功调用,编译器可以在必要时隐式地将Student转换为Person。
15.私有继承意味着 "用...来实现"。如果使类D私有继承于类B,
这样做是因为你想利用类B中已经存在的某些代码,
而不是因为类型B的对象和类型D的对象之间有什么概念上的关系。
16.尽可能地使用分层,必须时才使用私有继承
17.如果实例化一个模板一百次,你就可能实例化了那个模板的代码一百次。例如Stack模板,
构成Stack<int>成员函数的代码和构成Stack<double>成员函数的代码是完全分开的。
有时这是不可避免的,但即使模板函数实际上可以共享代码,
这种代码重复还是可能存在。这种目标代码体积的增加有一个名字:模板导致的 "代码膨胀"。这不是件好事。
18.明智使用私有继承
假如有个栈A,需要压入void*指针,即可以压入不同类类型的指针,这里会遇到这个问题,需要你压入的类型不同,如
有时候压入int的,有时候压入char类型的。
如果采用实现来规避这个问题,但有时候,有人误操作使用了栈A进行压入操作,这是有可能。为了避免这一点,我们可以
让栈A的构造函数设为protected,无法构造这个类A的对象了,避免有个进行对它操作了,那我们怎么解决不同类型压栈问题呢
,这里就用私用继承了,在一些接口类中,要求改变基类的实现,采用私有继承,
19.明智地使用内联,
内联函数的基本思想在于将每个函数调用以它的代码体来替换
可能会增加整个目标代码的体积,内联造成的代码膨胀也可能会导致不合理的页面调度行为
过多的内联还会降低指令高速缓存的命中率,从而使取指令的速度降低,因为从主存取指令当然比从缓存要慢。
20.文件间的编译依赖性降至最低
接口和实现的分离将大大节省重新编译和链接所花的时间
21.分离的关键在于,"对类定义的依赖" 被 "对类声明的依赖" 取代了
22.为了降低编译依赖性,我们只要知道这么一条就足够了:只要有可能,尽量让头文件不要依赖于别的文件;如果不可能,就借助于类的声明,不要依靠类的定义。
由于C++没有明确的将接口和实现分离,文件之间的编译依赖关系很大,
如果有一个文件代码发生变化,则可能影响其他文件,乃至整个项目。
因此,将对象实现细目隐藏于一个指针背后的目的,我们可以设计一个接口类。一个实现类,负责接口的实现
23.提供一个完整、最小的接口,用户就可以做任何他们想做的事,但类的接口不必再那样复杂
24.成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行
25.构造函数没有声明为explicit的情况下才会这样,因为explicit构造函数不能用于隐式转换
26.避免对指针和数字类型重载
27.无数现有的C++代码都依赖于使用了多年的伪标准库中的功能,
例如,声明在<iostream.h>,<complex.h>,<limits.h>等头文件中的功能
28.· 旧的C++头文件名如<iostream.h>将会继续被支持,尽管它们不在官方标准中。这些头文件的内容不在名字空间std中。
· 新的C++头文件如<iostream>包含的基本功能和对应的旧头文件相同,但头文件的内容在名字空间std中。
(在标准化的过程中,库中有些部分的细节被修改了,所以旧头文件和新头文件中的实体不一定完全对应。)
· 标准C头文件如<stdio.h>继续被支持。头文件的内容不在std中。
· 具有C库功能的新C++头文件具有如<cstdio>这样的名字。它们提供的内容和相应的旧C头文件相同,只是内容在std中。
29.尽量使用初始化而不要在构造函数里赋值,从纯实际应用的角度来看,有些情况下必须用初始化。
特别是const和引用数据成员只能用初始化,不能被赋值。 efftive C++ c++ --------------------编程问答-------------------- 一个问题: 我尝试封装HWND来作为子窗口控件的基类
在CommonControl中我写了这样一句话
virtual bool onCreate(void) = 0;
在TreeControl(继承自CommonControl)中我重写了onCreate函数
bool onCreate(LPCSTR p_hWndClass, LPCSTR p_szCaption, HWND p_hWndParent, HINSTANCE p_hInstance, int32_t p_posx, int32_t p_posy, int32_t p_height, int32_t p_width){}
神奇的是代码编译通过了,我不解 纯虚函数 其子类的实现 可以参数不同?那不就是 函数重载 而不是函数重写?纯虚函数这样也行?
补充:云计算 , 云安全