从基类调用虚方法

Calling a virtual method from the base class

本文关键字:方法 调用 基类      更新时间:2023-10-16

所以,基本上我正在创建一个包装器类,它创建一个简单的OpenGL应用程序。我的想法是,准备好后要有这样的东西:

#include "application.h"
#include "myClassDerivedFromApp.h"
int main()
{ 
    myClassDerivedFromApp app(1024, 768, "My App Name", 3.3 /*OpenGL Version*/);
    app.start();
    return 0;
}

基本上这个类封装了一个简单的OpenGL窗口,使用GLFW。其思想是,当您想要创建一个新应用程序时,您只需从application类(我正在编写的)派生您的类。有了这个新类,你只需要重写虚拟方法(mainLoop、initialize和回调),你就会有一个工作的应用程序。

下面是基类:

#pragma once
// Std library
#include <string>
// OpenGL related
#include <GLglew.h>
#include <GLFWglfw3.h>
// lh namespace
#include "camera.h"
#include "window.h"
namespace lh
{
    //!
    //! Class definition of a generic OpenGL Application. Receives the window size,
    //! the Application's name and OpenGL's version used.
    //!
    class Application
    {
    public:
        Application(int windowWidth, int windowHeight, std::string name, float versionOpenGL);
        virtual ~Application();
        void start();
    protected:
        virtual void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mode) = 0;
        virtual void mouseCallback(GLFWwindow* window, double xpos, double ypos) = 0;
        virtual void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) = 0;
        virtual void mainLoop() = 0;
        virtual void initialize() = 0;
    private:
        void execute();
        // Callbacks
        static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode);
        static void MouseCallback(GLFWwindow* window, double xpos, double ypos);
        static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
        // Attributes
        GLFWwindow* window_;
        int width_;
        int height_;
        std::string name_;
        int versionMajor_;
        int versionMinor_;
    };
}

因此,我所做的是将所有需要在派生类(位于protected)中创建的函数声明为纯虚函数。下面是实现:

void lh::Application::start()
{
    initialize();
    execute();
}
void lh::Application::execute()
{
    while (glfwWindowShouldClose(window_)) {
        glfwPollEvents();
        mainLoop();
        glfwSwapBuffers(window_);
    }
}

基本上方法start调用虚方法initialize,方法execute调用方法mainLoop。这样,如果我想创建一些新的东西,我就不必每次都设置glfw和窗口,我只需要从这个类派生并实现纯虚拟方法。

这是一个想法,但是Visual Studio报告一个错误,我正在调用一个纯虚拟函数,这可能意味着我不能做我目前正在做的事情。但是我没有看到其他方法(同时确保Application类仍然是抽象的)。

注意

我没有包括所有的实现(构造函数和回调函数),因为我认为它们与当前的问题无关(构造函数工作正常)。

编辑

我是这样测试这个类的:

#pragma once
#include "application.h"
class Teste :
    public lh::Application
{
public:
    Teste(int width, int height, std::string name, float versionOpenGL);
    ~Teste();
protected:
    void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mode);
    void mouseCallback(GLFWwindow* window, double xpos, double ypos);
    void scrollCallback(GLFWwindow* window, double xoffset, double yoffset);
    void mainLoop();
    void initialize();
};

和实现:

#include "teste.h"
#include <iostream>
Teste::Teste(int width, int height, std::string name, float versionOpenGL) 
  : Application(width, height, name, versionOpenGL)
{
}
Teste::~Teste()
{
}
void Teste::initialize()
{
    std::cout << "INTIALIZE" << std::endl;
}
void Teste::mainLoop()
{
    std::cout << "AAAAAAAA" << std::endl;
}
void Teste::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
}
void Teste::mouseCallback(GLFWwindow* window, double xpos, double ypos)
{
}
void Teste::scrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
}
编辑:

上面的代码运行良好。问题是,在构造函数中,我在最后调用start(),这是调用虚方法。将它从构造函数中移除并传递给main()函数使其正常工作。

当c++初始化一个派生类(您的Teste类)时,它将首先构造基类(您的Application类)。调用基类的构造函数时,派生类不可用。虚成员函数(execute)仍然是纯虚函数,因此错误是纯虚函数调用。

构造函数不应该调用虚函数,因为它不提供多态性。你可以为Application提供一个公共的start函数,并在构造函数之外调用它。

参见:Bjarne Stroustrup的c++风格和技术FAQ:我可以从构造函数调用虚函数吗?