Jun 24, 2009

c++ NOTE

1. 如果基类有多态行为,请把它的解构函数定义为 virtual.
考虑如下情形
BaseClass *ptr = createChildClassInstance();
// use ptr
delete prt;
如果不用 virtual 解构函数,delete 时候会出错。

2. 使用模板类必须指定模板实参(argument)
使用模板函数可以不指定模板实参,但是当编译器没办法推断出类型实参时,则必须指定
template<typename T>
int compare(const T&a, const T&b)
{
 if(a<b)
  return -1;
 if(b<a)
  return 1;

 return 0;
}

int main()
{
 cout << compare(1,2) << endl;
 cout << compare<double>(1,2.0) << endl;//必须指定
 cout << compare<string>("abc","abcd") << endl;//必须指定
 return 0;
}


3. 继承的选择
Public 继承说明``is-a''关系,基类的任一行为派生类都能够执行。想想鸟类和企鹅在飞行这个动作上的趣事,还有矩形可以增加长度而不改变宽度,正方形是矩形却不能这样做。

如果一个类不准备作为基类,那么全部函数都是 non-virtual。对于一个基类,其成员函数有三种选择,我们根据需要选择一种。意义分别如下(以 Person 类为例):

  1. pure virtual:只继承接口,继承类必须实现。强调特异性。比如“打招呼”这个成员函数,由于语言各异,可以设为 pure virtual.
  2. impure virtual:继承接口和一份缺省实现。特异性和不变性的平衡。比如“表示同意”这个函数,缺省为点头,这是大多数人的习惯。当然也有不同文化的人群用摇头表示同意。
  3. non-virtual:继承接口和一份强制实现。强调不变性。比如求身高这个函数。不同的人的求法都是一样的。

绝不重新定义继承而来的 non-virtual 函数。绝不重新定义继承而来virtual 函数的缺省参数值。

Virtual 接口的另一选择是 non-virtual interface (NVI).

Private 继承意思是is-implemented-in-terms-of,不继承接口,只继承实现,并利用有用的实现。
基类的所有 public 和 protected 成员都变成派生类的 private 成员,这是表明派生类并不表现为基类,我们只是利用基类的一些实现。

不要用 protected 继承。

4. 多态和虚函数

#include 
#include "early.h"

using namespace std;

int base::f() const { return 7; }
int derived::f() const { return 2;}
int main() {
  derived d;
  base* b1 = &d;
  base& b2 = d;
  base b3;
  // Late binding for both:
  cout << "b1->f() = " << b1->f() << endl;
  cout << "b2.f() = " << b2.f() << endl;
  // Early binding (probably):
  cout << "b3.f() = " << b3.f() << endl;
}
类 base 和 derived 都包含虚函数,称抽象基类。derived 中函数可以加上修饰符 virtual,含义是一样的。 声明 virtual 后,定义函数体时可不加 virtual,不算重载。但是定义函数体时如果去掉 const,算重载。

编译器为包含虚函数的类生成 VTABLE,为其对象生成 VPTR,因此base 和 derived 都有VTABLE 和 VPTR。

纯虚函数(function\_name() = 0)告诉编译器在 VTABLE中为函数保留一个间隔,但不放地址,其 VTABLE 是不完整的,不能生成这个类的对象。包含纯虚函数的类成纯抽象类。注意为纯虚函数定义函数体是可以的,派生类可以通过
base::function\_name 来访问。

抽象基类作用是为子类提供一个公共借口。

5. 名字掩盖Name hiding

几个名词
signature 函数的参数列表
overload  指同一个类(同一层次)中多个函数的函数名一样,signature不一样
redefine  指子类中对父类的函数重定义,signature和return type都要一样(const 好像不影响),override也是一种redefine
override  redefine并且父类的函数为虚函数


若父类有overload的函数,子类对其中一个进行redefine,所有其他的版本(除redefine的那个)都会被hidding
子类对其中一个进行修改(signature或return type),则所有版本都被hidding

6. 枚举常量不会占用对象的存储空间,它们在编译时被全部求值

7. 不要重新定义继承而来的数据成员

0 comments: