【问题标题】:So, why do I have to define virtual function in a base class?那么,为什么我必须在基类中定义虚函数呢?
【发布时间】:2021-12-25 22:13:03
【问题描述】:

我正在尝试创建一个简单的基本抽象类,其中包含一个虚函数和一个定义该虚函数的子类。在编译过程中运行以下会产生错误:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void speak();

};

class Cat : public Animal{
public:
    void speak() override {
        cout << "Meow!";
    }
};

int main() {
    Cat cat;
    Animal* base = &cat;
    base->speak();
}
// error LNK2001: unresolved external symbol "public: virtual void __thiscall Base::speak(void)" (?speak@Base@@UAEXXZ)

我的 IDE 建议在 Animal 中为 speak() 添加一个无用的定义,它可以工作:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void speak();
};

void Animal::speak() {

}

class Cat : public Animal{
public:
    void speak() override {
        cout << "Meow!";
    }
};

int main() {
    Cat cat;
    Animal* base = &cat;
    base->speak();
}

那么,为什么我必须在基类中定义虚函数?

相比之下,在Java中没有这种需要甚至可能性(这更有意义):

abstract class Animal {
    abstract void speak();
}

class Cat extends Animal {
    void speak() {
        System.out.println("Meow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.speak();
    }
}

【问题讨论】:

  • 您不必这样做。您必须通过在声明中添加 = 0 来告诉您的编译器它没有实现。
  • 虚拟方法可以提供“默认行为”,只有抽象方法会很不方便。
  • 否则,在通过指向基类的指针/引用(多态性)进行继承的情况下,它们不会被调用。
  • @tkausl 可以定义/实现纯虚函数。该定义是可选的,而不是被阻止的。

标签: c++ abstract-class virtual-functions function-definition


【解决方案1】:

您需要在基类中使用= 0 将其标记为“抽象”(或C++ 术语中的“纯虚拟”)。

class Animal {
public:
    virtual void speak() = 0;
};

【讨论】:

    【解决方案2】:

    在 C++ 中,如果一个类至少有一个纯虚函数,那么它就是抽象类。

    这门课

    class Animal {
    public:
        virtual void speak();
    
    };
    

    不是抽象类,因为在类中没有声明纯虚函数。

    而虚函数是通过在类定义的函数声明中使用纯说明符来指定的。

    也就是说要让类抽象,你应该像这样声明它的虚函数

    class Animal {
    public:
        virtual void speak() = 0;
    
    };
    

    编译器需要建立一个指向虚函数的指针表,其中将存储虚函数的实际地址。如果链接器无法解析虚函数的地址,则会发出错误。

    请记住,可以定义纯虚函数。例如你可以写

    class Animal {
    public:
        virtual void speak() = 0;
    
    };
    
    void Animal::speak()
    {
        std::cout << "The animal has issued a sound.\n";
    }
    

    在派生类中,您可以通过以下方式定义函数

    class Cat : public Animal{
    public:
        void speak() override {
            Animal::speak();
            cout << "Meow!";
        }
    };
    

    【讨论】:

      【解决方案3】:

      是的,应该定义非纯虚函数。

      [class.virtual]/12:

      在一个类中声明的虚函数应在该类中定义或声明为纯([class.abstract]),或两者兼而有之;无需诊断 ([basic.def.odr])。

      您可以提供定义,或将其标记为纯虚拟。

      class Animal {
      public:
          virtual void speak() = 0;
      };
      

      【讨论】:

        猜你喜欢
        • 2016-10-01
        • 2016-01-07
        • 1970-01-01
        • 1970-01-01
        • 2017-02-28
        • 1970-01-01
        • 2016-01-21
        • 2017-01-20
        相关资源
        最近更新 更多