我正在做大学课程,并试图用GLFW建立一个窗口。我一直在关注我们要关注的文档和视频系列(Youtube上Cherno的Hazel引擎),但遇到了抽象类的问题。
我真的很难理解指针和抽象,所以我真的很难理解我在做什么,但我相信它试图从Window调用继承的“create”函数来构建WinWindow(之所以这样命名是因为它是Windows操作系统特有的),但我在WinWindow的第9行得到一个错误C2259“'Engine::WinWindow'无法实例化抽象类”。cpp
有关守则如下:
窗H
#pragma once
#include "graphicsContext.h"
#include <string>
#include <functional>
namespace Engine {
class Event; // Be replaced
struct WindowProperties
{
std::string m_title;
unsigned int m_width;
unsigned int m_height;
bool m_isFullScreen;
bool m_isVSync;
WindowProperties(const std::string& title = "My Window", unsigned int width = 800, unsigned int height = 600, bool fullscreen = false) : m_title(title), m_width(width), m_height(height), m_isFullScreen(fullscreen) {}
};
class Window
{
public:
using EventCallbackFn = std::function<void(Event&)>;
virtual void init(const WindowProperties& properties) = 0;
virtual void close() = 0;
virtual ~Window() {};
virtual void onUpdate(float timestep) = 0;
virtual void onResize(unsigned int width, unsigned int height) = 0;
virtual void setVSync(bool VSync) = 0;
virtual void setEventCallback(const EventCallbackFn callback) = 0;
virtual unsigned int getWidth() const = 0;
virtual unsigned int getHeight() const = 0;
virtual void* getNativeWindow() const = 0;
virtual bool isFullScreenMode() const = 0;
virtual bool isVSync() const = 0;
static Window* create(const WindowProperties& properties = WindowProperties());
protected:
std::shared_ptr<GraphicsContext> m_context;
};
}
winWindow。H
#pragma once
#include "windows/window.h"
#include <GLFW/glfw3.h>
namespace Engine {
class WinWindow : public Window {
public:
WinWindow(const WindowProperties& properties);
virtual ~WinWindow();
void onUpdate();// override;
inline unsigned int getWidth() const override { return m_data.width; }
inline unsigned int getHeight() const override { return m_data.height; }
inline void SetEventCallback(const EventCallbackFn& callback) override { m_data.eventCallback = callback; }
void setVSync(bool enabled) override;
bool isVSync() const override;
private:
virtual void init(const WindowProperties& properties);
virtual void shutdown();
GLFWwindow* m_window;
struct windowData {
std::string title;
unsigned int width, height;
bool vSync;
EventCallbackFn eventCallback;
};
windowData m_data;
};
}
winWindow。cpp
#include "engine_pch.h"
#include "Platform/win/winWindow.h"
namespace Engine {
static bool GLFWinit = false;
Window* Window::create(const WindowProperties& properties) {
return new WinWindow(properties);
}
WinWindow::WinWindow(const WindowProperties& properties) {
init(properties);
}
WinWindow::~WinWindow() {
shutdown();
}
void WinWindow::init(const WindowProperties& properties) {
m_data.title = properties.m_title;
m_data.width = properties.m_width;
m_data.height = properties.m_height;
LOG_INFO("Window: {0} - ({1}, {2})", properties.m_title, properties.m_width, properties.m_height);
if (!GLFWinit) {
GLFWinit = true;
}
m_window = glfwCreateWindow((int)properties.m_width, (int)properties.m_height, m_data.title.c_str(), nullptr, nullptr);
glfwMakeContextCurrent(m_window);
glfwSetWindowUserPointer(m_window, &m_data);
setVSync(true);
}
void WinWindow::shutdown() {
glfwDestroyWindow(m_window);
}
void WinWindow::onUpdate() {
glfwPollEvents();
glfwSwapBuffers(m_window);
}
void WinWindow::setVSync(bool enabled) {
if (enabled)
glfwSwapInterval(1);
else
glfwSwapInterval(0);
m_data.vSync = enabled;
}
bool WinWindow::isVSync() const {
return m_data.vSync;
}
}
我也得到了一个单独的错误C3668,它说'Engine::WinWindow::SetEventCallback':带有覆盖说明符'覆盖'的方法没有覆盖任何基类方法。虽然我可能大错特错,但我相信这只是因为它目前还没有被使用。
我们非常感谢您在这些问题上提供的任何帮助,但您能否尽可能多地解释一下自己,以帮助我了解正在发生的事情以及正在发生的事情的决策,因为我真的很难做到这一点?
必须从WinWindow
中的Window
实现所有纯虚拟函数(声明中=0
的成员函数)。否则,WinWindow
将是一个抽象类(与Window
一样),无法创建抽象类的实例,但您正试图使用newwinwindow(properties)
创建类型为WinWindow
的实例(这就是错误告诉您的)。
您还没有重写和实现许多类,例如近
、onResize
等。
您不应忽略其他错误消息。这意味着在WinWindow
中声明函数时出错。
问题在于窗口中的虚拟函数具有以下签名:
void setEventCallback(const EventCallbackFn callback)
但是你假设的覆盖有签名:
void SetEventCallback(const EventCallbackFn& callback)
函数名不相同,参数类型也不相同(一个是引用,另一个不是)。重写函数必须与其重写的函数的签名相匹配。
也不要删除
覆盖
限定符。如果这样做,错误消息将消失,但它实际上不会解决问题。如果要从基类重写virtual
函数,请始终添加override
。如果你犯了一个错误,它会给出一个错误,这正是它存在的原因。因此,将override
添加到onUpdate
中,并使其与应该覆盖的virtual
功能相匹配:
void onUpdate(float timestep) override;
与问题中提到的问题无关的进一步说明:
还要注意的是,在现代C语言中几乎不应该直接使用
new
。使用std::unique\u ptr
事实上,我不明白为什么返回的是
Window*
,而不是WinWindow*
,所以请确保std::unique\u ptr
但是如果是这样的话,您也可以直接使用
WinWindow
的构造函数,而不是通过创建
方法。因此,创建代码是没有意义的。
还要注意,
内联
关键字是完全多余的。你应该移除它们。它们除了迷惑读者之外什么也不做(例如:你知道它们的意思吗?)。在类定义中直接定义的函数是自动内联的。
还要注意的是,您的类
WinWindow
没有遵循0/3/5规则,因为您的类正在管理一个资源(窗口句柄),并且您给了它一个析构函数,该析构函数可以执行一些非平凡的操作(销毁窗口),但是您没有实现语义正确的复制构造函数和复制分配操作符。因此,如果您碰巧隐式或显式地复制它,您的类将中断。当您直接使用WinWindow
的构造函数时,会发生这种情况,例如,如我上面建议的那样,在create
中按值返回。因此,只要你不解决这个问题,你就应该坚持使用std::unique\u ptr
/std::make\u unique
。
在这种情况下,正确的修复方法是使用正确的语义实现move构造函数和move赋值操作符。复制窗口在语义上没有意义(或者至少你实际上不想这么做),但是你可以将窗口句柄从一个对象移动到另一个对象。
诚然,这些都是相对先进的科目。如果只是提供了一个包装类,将C库(GLFW)包装在适当的C接口中,而不是手动执行此操作,则不会出现此问题。我希望你的讲师提供一个包装类,至少在窗口句柄本身周围。如果你还没有学习移动语义学和资源管理,对初学者来说,正确地做到这一点是困难的或不可能的。
我建议你在尝试这么复杂的事情之前,先从一本涵盖所有这些内容的好的入门书中学习。
我查过了,发现最接近的是这个,除了我没有任何向前的声明。我在基类中只有一个纯虚函数,我在子类中实现它,如下所示: 命令H 命令cpp 数字H 数字cpp 发生文件错误: 一个dd.cpp 添加H
我有两个方法和抽象类的接口,它们实现了这个接口并从它重写了一个方法。我可以实例这个抽象类,而不重写接口的其他方法吗?或者我可以用具有另一个签名的方法替换此方法吗? UPD:谢谢你的回答,我真的在我的问题上犯了错误。我是否可以使用匿名类来扩展我的抽象类,而不重写来自实现的所有方法?我如何理解DragonK的回答,不,我需要创建类,这将是扩展抽象类和重写其他方法?
我正在尝试实现上面提到的解决方案,但是在这里,我得到了一个错误“RowMapper是抽象的,不能实例化”和“表达式的非法开始”。下面正是我所说的
我正在学习OOP的概念。在阅读继承的过程中,我了解到在初始化子类之前必须先初始化超类,即所有超类的构造函数必须在子类构造函数之前运行。此外,我们还可以直接创建超级类的实例。对于例如。 现在,我遇到了抽象类。看来我们不能实例化一个抽象类。要使用抽象类,您必须从另一个类继承它,并为其中的抽象方法提供实现。 我的问题是,在实例化具体子类的同时,抽象超类的构造函数会在具体子类的构造函数之前被调用。如果是这
本文向大家介绍C#实现简单的Login窗口实例,包括了C#实现简单的Login窗口实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#实现简单的Login窗口。分享给大家供大家参考。具体实现方法如下: C# 制作登录窗体,登录成功之后正确的做法是关闭(close)登录窗体,而不是隐藏窗体(hide) FrmLogin窗体: Main方法入口: 希望本文所述对大家的C#程序设计有所帮助。
问题内容: 在Java中,可以扩展带有匿名类的接口,该类可以动态实现。例: (更多信息:http : //www.techartifact.com/blogs/2009/08/anonymous-classes-in-java.html#ixzz1k07mVIeO) 这在C#中可能吗?如果不是,那么有什么可行的替代方法而不必依赖于实现过多的子类? 问题答案: 不,您不能在C#中做到这一点-但通常,