美文网首页
C++ 虚函数

C++ 虚函数

作者: 不决书 | 来源:发表于2023-03-01 17:15 被阅读0次

正常情况下,我们在类继承中,如果使用相同的成员函数,结果输出按照下面的代码执行也是正确的

  class  Entry
   {
     public:
    std::string GetName() { return "Entry"; }
   };

 class Player : public Entry
  {
     private: 
     std::string m_Name;
      public:
     Player(const std::string& name)
        : m_Name(name) {}

     std::string GetName() { return m_Name; }
 };

 int main()
{
    Entry* e = new Entry();
    std::cout << e->GetName()  << std::endl;

    Player* p = new Player("David");
    std::cout << p->GetName() << std::endl;
    std::cin.get();
}

输出结果是
Entry
David

修改部分代码,再次运行,没有得到我们预期的结果,具体如下

   int main()
{
    Entry* e = new Entry();
    std::cout << e->GetName()  << std::endl;

    Player* p = new Player("David");
    std::cout << p->GetName() << std::endl;
        
        Entry* entry = new Player("David");
        // 这里输出的结果并不是我们预期的,而是"Entry"
        std::cout << Entry->GetName() << std::endl;
        
    std::cin.get();
}

执行后输出的结果为:
Entry
David
Entry

如果我们编写一个通用的输出函数,结果就不对了,下面是在上例增加的代码

void print(Entry* entry)
{
    std::cout << entry->GetName()  << std::endl;
}

int main()
{
    Entry* e = new Entry();
    print(e);

    Player* p = new Player("David");
    print(p);
        
    std::cin.get();
}

执行输出的结果为:
Entry
Entry

通过虚函数virtual,我们就可以成功的覆盖,显示预期的结果,具体修改如下

 class  Entry
   {
     public:
        // 虚函数
    virtual std::string GetName() { return "Entry"; }
    };

// .....

void print(Entry* entry)
{
    std::cout << entry->GetName()  << std::endl;
}

int main()
{
    Entry* e = new Entry();
    print(e);

    Player* p = new Player("David");
    print(p);
        
    std::cin.get();
}

输出结果就是正确的:
Entry
David

为了更好得提现类继承,方法的覆盖,我们采用关键字override 来修饰,代码可读性更好,同时还可以检查覆盖的方法是否和基类一致,完整代码

  #include <iostream>
class  Entry
{
public:
    virtual std::string GetName() { return "Entry"; }
};

class Player : public Entry
{
private: 
    std::string m_Name;
public:
    Player(const std::string& name)
        : m_Name(name) {}

    // 覆盖(重写)基类的方法
    std::string GetName() override { return m_Name; }
};

void Print(Entry* entry)
{
    std::cout << entry->GetName() << std::endl;
}

    int main()
    {
        Entry* e = new Entry();
        Print(e);

        Player* p = new Player("David");
        Print(p);

        std::cin.get();
    }

代码可以正确的输出
Entry
David

虚函数本质是在编译器中建立一个虚拟表,根据基础类与基类的关系,这样编译器会根据执行的实例调用不同的方法,这里虽然有性能上的损耗,但是可以忽略不考虑

如果我们将基类的函数为纯虚函数,那就意味着,我们需要继承给基类的派生类去实现这个方法,纯函数的定义如下

class  Entry
  {
     public:
        // 纯虚函数的定义,直接让函数等于 0
    virtual std::string GetName() = 0;
  };

// ……

int main()
    {
        Entry* e = new Entry();
                // 这里调用纯虚函数的GetName() 方面就会报错
        Print(e);

        Player* p = new Player("David");
        Print(p);

        std::cin.get();
    }

1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): error C2259: “Entry”: 无法实例化抽象类
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(5,8): message : 参见“Entry”的声明
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): message : 由于下列成员:
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): message : “std::string Entry::GetName(void)”: 是抽象的
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(8,22): message : 参见“Entry::GetName”的声明

基类中定义的纯虚函数,是要求派送类中必须要实现的

// 对于多重继承的虚函数,我们为单独设置一个打印虚拟类,这样就不需要考虑具体是什么类了,完整的代码

 #include <iostream>

class Printable 
{
public:
    virtual std::string GetClassName() = 0;
};

class  Entry: public Printable
{
public:
    virtual std::string GetName() { return "Entry"; };
    std::string GetClassName() override { return "Entry"; }
};

class Player : public Entry
{
private: 
    std::string m_Name;
public:
    Player(const std::string& name)
        : m_Name(name) {}

    // 覆盖(重写)基类的方法
    std::string GetName() override { return m_Name; }
    std::string GetClassName() override { return "Player"; }
};

void Print(Printable* entry)
{
    std::cout << entry->GetClassName() << std::endl;
}


    int main()
    {
        Entry * e = new Entry();

        Entry * p = new Player("David");
        
        Print(e);
        Print(p);

        std::cin.get();
    }

运行输出结果
Entry
David

相关文章

网友评论

      本文标题:C++ 虚函数

      本文链接:https://www.haomeiwen.com/subject/caqdldtx.html