C ++:当派生类中的方法在基础中不是虚拟时,声明虚拟方法是否合法?

时间:2013-02-26 23:38:06

标签: c++ inheritance virtual-method

基类专门声明该方法是非虚拟的。 它适用于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. 为什么会这样?

3 个答案:

答案 0 :(得分:6)

  

1。这是合法的吗?

  

2。它为什么有效?

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

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

然而,这不会以任何方式影响sayhi::hi():特别是,在隐藏它的派生类中仅存在virtual函数不会使其 virtual。因此,通过指针或对 base sayhi的实例的引用来调用函数时,您不能指望虚拟调度工作:

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"!    

答案 1 :(得分:2)

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

隐藏基类方法(非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,因为hi中的sayhi不是虚拟的。然而

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

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

答案 2 :(得分:0)

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