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

C++: Is it legal to declare a method virtual in a derived class when it wasn't virtual in the base?

本文关键字:方法 声明 virtual 派生 是否 基类 C++ 虚拟      更新时间:2023-10-16

基类明确声明该方法为非虚拟方法。它适用于Visual Studio 2008,2010和2012以及IDONE使用的任何编译器(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. 为什么有效?

1 .合法吗?

是的

阿拉伯数字。为什么有效?

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

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

但是,这不会以任何方式影响sayhi::hi():特别是,在隐藏它的派生类中仅存在virtual函数并不能使其virtual 。因此,在通过指针或对类实例的引用调用函数时,不能期望虚拟调度工作 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"!    
这是

合法的。从那一刻起,该方法在 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,因为该方法是动态调用的。

这是

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