Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532738
  • 博文数量: 137
  • 博客积分: 3170
  • 博客等级: 中校
  • 技术积分: 1455
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-17 11:47
文章分类

全部博文(137)

文章存档

2015年(2)

2013年(1)

2012年(6)

2011年(5)

2010年(62)

2009年(61)

我的朋友

分类: C/C++

2010-11-05 10:34:11

以下主要节选自林锐韩永泉的书。
面向对象的观点;
对象的概念;
信息隐藏与类的封装;
类的继承特性;
派生类可以调用基类的函数(虚函数也可)来实现自己的类:

class A {
public:
void Func1(void);

  void Func2(void);
};

class B : public A
{
  public:
     void Func3(void)
     {
         A::Func1();
          ....
         A::Func2();
     }
};
类的组合特性;
动态特性:
一般程序的功能是在编译时候确定的,静态特性,如果程序的功能是在运行时确定,动态特性。
c++的虚函数,抽象基类,动态绑定,多态构成了动态特性。
为何要有虚函数?
可以使接口函数统一,实现动态绑定。一旦类的一个函数被声明为虚函数,那么其派生类的相应函数也自动成为虚函数,为了程序清晰性,每个层次都加上virtual关键字。
为何要抽象基类?
不能实例化为对象的类,称为抽象类,唯一目的是让其派生类继承并实现它的接口方法,也被成为抽象基类。
如果基类虚函数声明为纯虚函数,那么该类被定义为抽象基类。纯虚函数是在声明时将其"初始化"为0的函数。
例子:

                                                                                      
抽象基类把数据和实现函数都隐藏在实现类中,在抽象类中提供丰富的接口函数 ,这些函数是public的纯虚函数,这样的抽象基类叫做接口类(Interface).
抽象基类不能实例化,如果实现类被完全隐藏,也就是我们看不到实现类,那么抽象基类必须提供接口来创建实现类的对象!一般用静态成员函数。
具有虚函数的类称为多态类,c++为每个多态类至少创建一个虚函数表(vtable),其实是一个函数指针数组, 其中存放着这个类所有虚函数的地址及该类的类型信息,也包括那些继承但未改写(overrides)的虚函数。
关于成员函数的重载、覆盖与隐藏:
g++中,如果派生类中有一个纯虚函数没有实现 ,那么派生类仍为抽象类,无法实例化。                                         
成员函数被重载特征:
具有相同作用域(即同一个类中定义) ;
函数名字相同;
参数类型、顺序或数目不同(包括const参数和非const参数) ;
virtual关键字可以可无。
覆盖是指派生类重新实现(或改写)了基类的成员函数,特征:
函数名称相同;
参数列表完全相同;
基类函数必须是虚函数,virtual关键字告诉编译器,派生类中相同的成员函数应该放到vtable中,替换基类相应函数的槽位。
隐藏规则:
派生类的函数与基类的函数同名,但是参数列表有所差别,此时,不论有无virtual关键字,基类的函数在派生类中被隐藏(注意与重载区分);
派生类的函数与基类函数同名,参数列表也相同,但是基类函数没有virtual关键字。此时基类的函数在派生类中被隐藏(注意与覆盖区分)。
应该让程序的行为依赖于对象的真实类型,而不是依赖于指针类型!

#include <iostream>
using namespace std;
class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    void g(float x ){ cout << "Base::g(float)" << x << endl;}
    void h(float x ){ cout << "Base::h(float)" << x << endl;}
};
class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; } //构成重载
    void g(int x ){ cout << "Derived::g(int)" << x << endl;} //
    void h(float x ){ cout << "Derived::h(float)" << x << endl;}
};
  int main(void)
{
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
        //好:程序的行为依赖于对象真实类型
    pb->f(3.14f); //
覆盖
    pd->f(3.14f);

    pb->g(3.14f); //隐藏
    pd->g(3.14f);

    pb->h(3.14f); //隐藏
    pd->h(3.14f);
    return 0;
}


关于虚函数调用语句的参数类型检查?
关于名空间:
对于模块的划分,对于代码的清晰度,都有好处;既不能滥用也不能因噎废食不用。研究一下还是能用好的,可以考虑google code里的protobuf名空间的使用方法和其他优秀开源项目的。
异常处理:

释放空指针:
p=NULL
delete p; 这种行为是安全的。


阅读(911) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-05 16:48:51

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com