【问题标题】:Calling a virtual method from the base class从基类调用虚方法
【发布时间】:2015-07-14 18:50:07
【问题描述】:

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

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

所以,基本上这个类使用 GLFW 封装了一个简单的 OpenGL 窗口。这个想法是,当您想创建一个新应用程序时,您只需从 Application 类(我正在编写)派生您的类。使用这个新类,您只需覆盖虚拟方法(mainLoop、initialize 和回调),您将拥有一个工作应用程序。

这是基类:

#pragma once

// Std library
#include <string>
// OpenGL related
#include <GL\glew.h>
#include <GLFW\glfw3.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() 函数使其工作正常。

【问题讨论】:

  • 确切的错误信息是什么?
  • R6025 - 纯虚函数调用
  • 由于这个类有纯虚函数,你不能直接实例化它。如果你试图为了测试,那可能会导致问题。你的另一个问题是,当你从这个类派生一个类时,start() 将调用execute(),它在基类中是私有的,因此不与子类共享......不确定这是否是有意的。
  • 你想要的应该可以工作 (ideone.com/SKkuWf) 我目前能想到的唯一原因是在构造函数或析构函数中调用虚函数
  • 为了好玩,给自己写一个简单的基类和子类,在构造函数和析构函数中打印出类的名称,以查看调用的顺序。应该清除您的任何剩余问题。

标签: c++ opengl polymorphism glfw


【解决方案1】:

当 C++ 初始化派生类(您的 Teste 类)时,它将首先构造基类(您的 Application 类)。 调用基类的构造函数时,派生类不可用。虚成员函数(execute)仍然是纯虚函数,所以报错是纯虚函数调用。

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

见:Bjarne Stroustrup's C++ Style and Technique FAQ: Can I call a virtual function from a constructor?

【讨论】:

    猜你喜欢
    • 2011-01-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多