wly603

C++中多态性、类成员的访问问题

概要:

     C++的多态性是通过关键字virtual指定的, 而Java中,动态绑定是默认的处理方式,java中不需要将方法声明为虚方法。

     因此,在C++中要结合类成员的访问控制符、virtual关键字,来分析调用的是哪个成员函数,是否发生多态。

 

一、规则总结

   1、对象只能访问类的public成员,对象只能访问本类声明的public成员和public函数

   2、派生类可以访问父类的public、protected成员

   3、有继承时,public继承,继承后父类成员的属性不变

                      protected继承,继承后父类public成员变为protected

                      private继承,继承后父类public、protected成员变为private

 

二、程序举列

   1、对象只能访问本类声明的public成员和public函数

      

例1
#include "iostream"
using  namespace std;


class Base
{
public :
 virtual    void fun()
    {
        print();
    }

/* void print() //注释掉了,则Base中没有定义print()函数
    {
        printf("Base print\n");
    }*/

};

class Derive : public Base
{
public :
    void fun()
    {
        print();
    }

    void print()
    {
        printf("Derive print\n");
    }
};

int main()
{
    Base b,*pBase;

    Derive d,*pDeruve;

    cout<<"-----------------------"<<endl;
    pBase = &b;
    pBase->fun();
    pBase->print();  //出错


    cout<<"--------------------"<<endl;    
    pDeruve = &d;
    pDeruve->fun();
    pDeruve->print();

    cout<<"----------------------"<<endl;
    pBase = &d;
    pBase->fun();
    pBase->print();  //出错

}

该程序会出现如下错误:

     error C2065: 'print' : undeclared identifier
     error C2039: 'print' : is not a member of 'Base'

原因:因为基类中没有定义print函数,当然就不能访问了。本类的指针只能访问本类中声明的public成员

 

   2、多态性测试

  

例2
#include "iostream"
using  namespace std;


class Base
{
public :
  virtual    void fun()
    {
        print();
    }

  void print() //virtual 
    {
        printf("Base print\n");
    }

};

class Derive : public Base
{
public :
    void fun()
    {
        print();
    }

    void print()
    {
        printf("Derive print\n");
    }
};

int main()
{
    Base b,*pBase;

    Derive d,*pDeruve;

    cout<<"-----------------------"<<endl;
    pBase = &b;
    pBase->fun();
    pBase->print();


    cout<<"--------------------"<<endl;    
    pDeruve = &d;
    pDeruve->fun();
    pDeruve->print();

    cout<<"----------------------"<<endl;
    pBase = &d;
    pBase->fun();
    pBase->print();

}

    该程序中,基类定义了fun函数和print函数,其中fun函数是虚函数。当让基类的指针指向派生类对象时,通过基类指针调用fun函数时,实际上调用的就是派生类的fun函数(多态性)。而当用基类指针调用print函数时,由于基类中定义了print函数,所以可以访问。又由于print函数不是虚函数,所以调用的是基类的print函数

输出结果为:

      

   

3、基类成员函数调用virtual函数

  

例3
#include "iostream"
using  namespace std;

class Base
{
public :
      void fun()
    {
        print();
    }

   virtual void print() // virtual
    {
        printf("Base print\n");
    }

};

class Derive : public Base
{
public :
    void fun()
    {
        print();
    }

    void print()
    {
        printf("Derive print\n");
    }
};

int main()
{
    Base b,*pBase;

    Derive d,*pDeruve;

    cout<<"-----------------------"<<endl;
    pBase = &b;
    pBase->fun();
    pBase->print();


    cout<<"--------------------"<<endl;    
    pDeruve = &d;
    pDeruve->fun();
    pDeruve->print();

    cout<<"----------------------"<<endl;
    pBase = &d;
    pBase->fun();
    pBase->print();

}

print是虚函数,pBase->print()由于多态性,调用派生类的成员函数。在pBase->fun()中,由于fun是基类的public函数,且不是虚函数,所以直接调用基类的fun函数,在fun函数中,它调用了基类的print函数,这类似于pBase->print(),由于多态性也调用了派生类的print函数;

输出结果:

  

注意:如果是基类的构造函数中,调用了print函数(此时print为虚函数),即

            Base()
            {
                   printf("Base 构造函数 ");
                   print();
              }

     当定义一个派生类对象时,基类的构造函数会先调用,此时基类构造函数中调用的是基类的print函数本身,不会发生多态。

    书《Effective C++ third edition》中解释如下:

           在derived class对象的base构造期间,对象的类型是base class,而不是derived class,此时基类的virtual 函数可看做不是虚函数

 

(完)

posted on 2012-05-19 13:50  wly603  阅读(1703)  评论(3编辑  收藏  举报

导航