Just a little smile ^ ^

yoyo_zeng

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

. 面向对象编程

 

 

 

virtual函数,启用动态绑定,只需在类内部的成员函数中声明,不能用在类定义体外部的函数定义中.

 

protected成员

 

可以被派生类对象访问, 其余同private权限. 派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型的对象的protected没有访问权限.

 

 

 

2.1 派生类

myclass.h文件

 class myclass
{
      
      public:
        
        operator int () const {return m_i;} //转换操作符

      friend class otherclass; //友元
      
      myclass():m_i(0), m_i(0.5), m_i2(0){m_i = 0; …} /*初始化,无返回值,不能声明为const,
      
      初始化列表一定会先于函数体执行,无论显示或隐式初始化,此时成员变量已经有值.
      
      如果没有对成员变量显示初始化,编译器会隐式地使用成员类型的默认构造函数,
      
      内置类型无默认构造函数,则编译器尝试隐式初始化失败,此时必须显示初始化或在函数体中赋值.
      
      无默认构造函数的类类型成员,以及const或者引用类型成员,必须在构造函数初始化列表中初始化.
      
      成员初始化顺序是定义成员的顺序.
      
      如果无构造函数,编译器会生成默认构造函数,如果有显示定义构造函数,则编译器不会生成默认构造函数.*/

      myclass(int i):m_i2(0),m_i(i){} //可被重载
      
      bool inlinefunc() {...} //inline函数

         inline void func1(); //inline函数,可以在声明中引用inline,也可在定义中引用
      
      const myclass& func2() const; /*普通成员函数,返回调用对象的引用,const成员函数必须返回const对象的引用.const对象只能使用const func2()成员函数.非const对象也可调用.*/
      
      myclass func2(int i); //重载函数
      
      myclass& func2(); /*重载函数,非const对象可以调用,非const对象调用fun2()函数时,非const func2()成员函数优先级大于const func2()成员函数.*/
      
      typedef  int MYINT;
      
      MYINT func3(MYINT i);
      
      bool equal(myclass m);
      
      static void staticfunc(void);
      
      virtual void virtualfunc(void);
      
      virtual void virtualfunc2(void);
  void func3(void);
public: int m_i2; private: const int m_i; //const成员变量,必须在构造函数初始化列表中初始化. static float m_f; //static 成员变量 myclass *m_class; //前向声明 mutable char c; //可变数据成员,在const成员函数中也可以修改. static myclass m_static_class; //static可以是该成员所属的类类型. //myclass m_class; //error };

 

 

deriveclass.h文件

class deriveclass: privated/public/protected superclass

 

{

 

         自己的成员函数;

 

         继承的成员函数;

 

         自己的成员变量;

 

         继承的成员变量; //在派生类中可以使用publicprotected,但是不能访问privated.

 

};

 

 

 

2.2 虚函数

 

 

 虚函数是在运行时期才确定;非虚函数在编译时期根据对象确定。

函数名字的查找的继承:首先确定调用函数的对象,引用和指针类型,如果在该类中查找不到此函数,则在基类链中寻找,如果找不到,则编译报错,找到了就执行常规函数检查是否调用合法;

如果合法,编译器生成代码,如果是通过引用和指针调用且为虚函数,则编译器生成代码以确定对象的动态类型运行哪个版本,否则直接生成代码调用函数。

 

 1 class derivedclass :public myclass
2
3 {
4
5 public:
6
7 derivedclass(void): m_di(0), myclass(); //首先调用各基类的构造函数,
8
9 virtual ~derivedclass(void); /*首先运行派生类的析构函数,然后按继承层次一次向上调用各基类析构函数. */
10
11 void virtualfunc(void); /*如果需要调用基类的函数,必须明确使用域操作符 obj->myclass::virtualfunc();*/
12
13 void virtualfunc2(int); /*没有重定义虚函数virtualfunc2(),所以virtualfunc2(int)屏蔽virtualfunc2(),
                  derivedclass dc; 不能直接调用dc.virtualfunc2(). 必须通过作用域操作符::, dc.myclass::virtualfunc(); 但是动态绑定可以调用:derivedclass dc; myclass *pmc = &dc; pmc->virtualfunc2()
*/
14
15/*对于非虚函数,在编译时期根据调用该函数的对象,引用或者指针类型而确定,所以如果是动态绑定,derivedclass dc; myclass *pmc = &dc; pmc->func3()实际调用的是基类的func3(),*/
   void func3(void);

16
17
18
19 derivedclass(const derivedclass & d): myclass(d), m_di(d.m_di), c(0){}
20
21 //复制构造函数
22
23 derivedclass& operator = (const derivedclass &d) //赋值操作符
24
25 {
26
27 if (this != &d)
28
29 {
30
31 myclass::operator = (d);
32
33 m_di = d.m_di;
34
35 }
36
37 return *this;
38
39 }
40
41
42
43 private:
44
45 int m_di; //自己的成员变量;
46
47 mutable char c; /*与基类成员同名,屏蔽基类成员, 但是可以通过myclass::c访问被屏蔽的基类成员c. */
48
49 };



派生类中虚函数的声明必须与基类中的定义方式完全匹配,有一个例外:返回基类型的引用(或指针)的虚函数.派生类中的虚函数可以返回基类函数所返回类型的派生类的引用(或指针). 即可返回基类或派生类的引用或指针.

 

 

 

一旦在基类声明为虚函数, 派生类中也是虚函数.

 

 

 

函数调用触发动态绑定动态必须满足两个条件,第一必须指定为虚函数,第二不许通过基类类型的引用或指针进行函数调用.

 

 

 

可将基类类型的引用绑定至派生类对象的基类部分,也可用基类指针指向派生类对象. 运行时才能确定实际类型. 编译其编译的时候都当作基类类型对象,

 

 

 

 

 

 1 myclass& func(const myclass& obj);
2
3 myclass& func(const myclass* obj);
4
5 myclass superobj;
6
7 func(superobj);
8
9 myclass * psuperobj = &superobj;
10
11 func(psuperobj);
12
13 //动态绑定:
14
15 derivedclass derivedobj;
16
17 func(derivedobj); /*引用的是派生类的基类部分,如果调用派生类定义的成员则出错. */
18
19 psuperobj = &derivedobj;
20
21 func(psuperobj); /*指针指向的是派生类中的基类部分,如果调用派生类定义的成员则出错. */
22
23 psuperobj-> virtualfunc(); //运行是才能确定,调用与动态类型对应的函数
24
25 psuperobj->derivedfunc(); /*出错, 在编译时期确定的类型为myclass,所以只能访问基类部分. */
26
27
28
29 myclass& func2(myclass obj);
30
31 func2(derivedobj); /*派生类对象传递给基类对象,派生类对象被切割,形参在编译和运行的时候都是基类类型对象, 派生类对象的基类部分被复制到基类对象(通过基类构造函数复制到临时变量. */


 

 

构造函数和复制控制成员不能继承. 除了初始化自己的成员以外,还要通过基类的构造函数初始化基类的成员,可以使用合成的默认构造函数. 不能直接调用基类的基类的构造函数初始化基类的基类.

 

 

 

2.3 虚析构函数

 

 

 

virtual~derivedclass(void);

 

析构动态绑定对象时, 需要虚析构函数保证运行适当的析构函数.

 

构造函数不能定义为虚函数, 因为构造函数是在对象完全构造之前运行的,在构造函数运行的时候,对象的动态类型并不完整.

 

赋值操作符也不要定义为虚函数, 因为虚函数必须在基类和派生类中具有同样的形参,形参为基类对象的引用.

 

 

 

1 class derivedclass : private myclass
2
3 {
4
5 public:
6
7 using int m_i2; /*可以使用using声明, 修改恢复成员的访问级别,但不能使访问级别比基类中原来指定的更严格或者宽松. */
8
9 }



 

 

2.4 纯虚函数

 

 

 

1 class purevirtualclass //抽象基类
2
3 {
4
5 public:
6
7 void purevirtualfunc(myclass mine) const = 0; //纯虚函数
8
9 };



纯虚函数为派生类提供了可以覆盖的接口,但是这个类中的版本绝不会调用,而且不能创建purevirtualclass的类对象.

 

如果派生类没有实现纯虚函数,则派生类也为抽象类.

posted on 2011-09-29 15:43  yoyo_zeng  阅读(218)  评论(0编辑  收藏  举报