覆盖和多态的条件

来源:互联网 发布:歌词有傻瓜的网络歌曲 编辑:程序博客网 时间:2024/03/29 10:13

覆盖和多态的条件

覆盖的条件

一.必须是成员函数
•只有类的成员函数才能被声明为虚函数,全局函数和类的静态成员函数都不能被声明为虚函数

virtual void global (void); // 错误class A  {     static virtual void staticNumb (void); // 错误  };

二.必须是虚函数

•只有基类中被virtual关键字声明为虚函数的成员函数才能被子类覆盖

class A {     void foo (void); };–class B : public A  {    virtual void foo (void); // 隐藏A::foo  };–class C : public B  {     void foo (void); // 覆盖B::foo  };–class D : public C  {     void foo (void); // 覆盖C::foo  };

三.函数签名必须相同

•虚函数在子类中的覆盖版必须和该函数的基类版本拥有完全相同的签名,即函数名、形参表和常属性严格一致

class A  {     virtual void foo (void);  }–class B : public A  {     virtual void bar (void); // 函数名不一致     virtual void foo (int); // 形参表不一致     virtual void foo (void) const; // 常属性不一致     void foo (void); // 覆盖A::foo   };

四.返回同类型的基本类型或对象

•如果基类中的虚函数返回基本类型的数据或类类型的对象,那么该函数在子类中的覆盖版本必须返回相同类型的数据或对象,否则将引发编译错误

class A  {     virtual void foo (void);     virtual int bar (void);     virtual X hum (void);  };–class B : public A  {     void foo (void);     int bar (void);     X hum (void);  };

五.返回类的指针或引用允许协变

•如果基类中的虚函数返回类类型的指针或引用,那么该函数在子类中的覆盖版本可以返回其基类版本返回类型的公有子类的指针或引用——类型协变

–class X { ... };–class Y : public X { ... };–class A  {     virtual X* foo (void);     virtual X& bar (void);  };–class B : public A  {     Y* foo (void);     Y& bar (void);  };

六.访控属性可以不同
•无论基类中的虚函数位于该类的公有、私有还是保护部分,该函数在子类中的覆盖版本都可以出现在该类包括公有、私有和保护在内的任何部分

–class A  {  public: virtual void foo (void);  };–class B : public A  {     private: void foo (void);  };–A* a = new B;  a->foo (); // 调用B::foo,虽然其为私有成员

重载,覆盖和隐藏

一.重载、覆盖和隐藏

•重载必须在同一个作用域中,包括通过using声明引入的

•覆盖要满足一系列特殊条件

•子类与基类的同名成员函数,不满足重载和覆盖的条件,且能正常通过编译,则必然构成隐藏

class Base  {     ① virtual void foo (void);     ② virtual void foo (void) const;  };–class Derived : public Base  {     ③ virtual void foo (void);     ④ virtual char foo (void) const;  };

①和②构成重载
③和④构成重载
③隐藏②覆盖①
④隐藏①覆盖②出错

多态的条件

一.指针和引用

•多态特性除了需要在基类中声明虚函数以外,还必须借助指针或者引用调用该虚函数,才能表现出来

–Rectangle r (...);  Circle c (...);  Shape sr = r;  sr.draw (); // 调用Shape::draw  Shape sc = c;  sc.draw (); // 调用Shape ::draw

二.this指针

•调用虚函数的指针也可能是成员函数中的this指针,只要它是一个指向子类对象的基类指针,同样可以产生多态

–class A  {     virtual void foo (void) { ... };     void bar (void)     {        foo (); // this->foo (),调用B::foo }  };–class B : public A  {     void foo (void) { ... };  };–B b;  b.bar ();

三.构造和析构函数

•当基类的构造函数被子类的构造函数调用时,子类对象尚不能说是子类类型的,它只表现出基类类型的外观和行为。这时调用虚函数,它只能被绑定到基类版本

–class A  {     A (void)     {         foo (); // 调用A::foo     }     virtual void foo (void) { ... };  };–class B : public A  {     void foo (void) { ... };  };–B b;

•当基类的析构函数被子类的析构函数调用时,子类对象已不再是子类类型的了,它只表现出基类类型的外观和行为。这时调用虚函数,它只能被绑定到基类版本

–class A  {     ~A (void)      {         foo (); // 调用A::foo      }      virtual void foo (void) { ... };  };–class B : public A  {      void foo (void) { ... };  };–B b;

•在基类的构造和析构函数中调用虚函数,绝不可能表现出多态性。实际被调用的一定是基类的原始版本,而非子类的覆盖版本

•在构造或析构函数中通过已构造完毕或尚未析构的对象调用虚函数,其多态性不受任何影响

阅读全文
0 0