【问题标题】:C++: Is it legal to declare a method virtual in a derived class when it wasn't virtual in the base?C ++:在派生类中声明一个虚拟方法是否合法,而它在基类中不是虚拟的?
【发布时间】:2013-02-26 23:38:06
【问题描述】:

基类明确声明该方法是非虚拟的。 它适用于 Visual Studio 2008、2010 和 2012 以及 whatever compiler ideone uses (gcc 4.7+ ?)。

#include <iostream>

class sayhi
{
public:
    void hi(){std::cout<<"hello"<<std::endl;}
};

class greet: public sayhi
{
public:
    virtual void hi(){std::cout<<"hello world"<<std::endl;}
};


int main()
{
    greet noob;
    noob.hi(); //Prints hello world
    return 0;
}

这也有效 - 该方法在基类中是私有且非虚拟的:

#include <iostream>

class sayhi
{
private:
    void hi(){std::cout<<"hello"<<std::endl;}
};

class greet: public sayhi
{
public:
    virtual void hi(){std::cout<<"hello world"<<std::endl;}
};


int main()
{
    greet noob;
    noob.hi(); //Prints hello world
    return 0;
}

我的问题是:

  1. 合法吗?
  2. 为什么有效?

【问题讨论】:

    标签: c++ inheritance virtual-functions


    【解决方案1】:

    1 .合法吗?

    是的

    2 。为什么会起作用?

    没有什么可以阻止您在派生类中声明与基类的成员函数同名的成员函数。您在派生类中的函数将简单地隐藏基类的函数。顺便说一句,如果派生类的函数恰好是virtual,那么子类可能会覆盖它:

    class howdy : public greet
    {
    public:
        // Overrides greet::hi()
        virtual void hi() { std::cout << "howdy world" << std::endl; }
    };
    

    但是,这不会以任何方式影响sayhi::hi():特别是,在隐藏它的派生类中仅仅存在virtual 函数不会这样做 @987654325 @。因此,在通过指针或对 basesayhi 的实例的引用调用函数时,您不能期望虚拟调度起作用:

    sayhi noob;
    noob.hi(); // Will NOT print "hello world"!
    
    greet gentleman;
    sayhi* p = &gentleman;
    p->hi(); // Will NOT print "hello world"!
    
    howdy neighbor;
    p = &neighbor; 
    p->hi(); // Will NOT print "howdy"!
    
    greet* pG = &neighbor;
    pG->hi(); // WILL print "howdy"!    
    

    【讨论】:

      【解决方案2】:

      这是合法的。从那时起,该方法在greet 的派生类中变为virtual

      基类方法被隐藏(与非virtual 一样)。

      通过greet 指针调用方法将动态解析调用。通过sayhi 调用它会静态地解决它。

      举个例子:

      class sayhi
      {
      public:
          void hi(){std::cout<<"hello"<<std::endl;}
      };
      
      class greet: public sayhi
      {
      public:
          virtual void hi(){std::cout<<"hello world"<<std::endl;}
      };
      
      class greetuniverse: public greet
      {
      public:
          virtual void hi(){std::cout<<"hello universe"<<std::endl;}
      };
      

      以下

      sayhi* p = new greetuniverse;
      p->hi();
      

      将打印hello,因为hisayhi 中不是虚拟的。不过

      greet* p = new greetuniverse;
      p->hi();
      

      将打印hello universe,因为该方法是动态调用的。

      【讨论】:

        【解决方案3】:

        这是合法的。通过将派生类中的函数命名为虚拟函数,您是在告诉编译器在运行时检查派生类的方法以在转到基类之前检查函数的实现。

        【讨论】:

          猜你喜欢
          • 2020-10-21
          • 1970-01-01
          • 1970-01-01
          • 2013-02-14
          • 1970-01-01
          • 1970-01-01
          • 2016-03-31
          • 2016-05-04
          • 2011-09-30
          相关资源
          最近更新 更多