C++:使用来自抽象 class 的指针来访问派生 classes 的方法; derived class 似乎也是抽象的
C++: Use pointer from abstract class for accessing method of derived classes; derived class apears to be abstract as well
我已经查找了 2 个小时(主要是在此站点上)以了解我在使用 C++ 编码时遇到的问题。我有一个抽象基础 class,看起来像这样:
Screen.hpp
#include <SFML/Graphics.hpp>
class Screen {
public:
virtual ~Screen();
virtual void Init() const = 0;
virtual void Render(sf::RenderWindow &window) const = 0;
virtual void Update(sf::RenderWindow &window, sf::Time &deltaTime) const = 0;
virtual void EventTriggered(sf::RenderWindow &window, sf::Event &event) const = 0;
};
接下来我声明了一个 class 派生自基数 class:
Splashscreen.hpp
#include "Screen.hpp"
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init();
void Update(sf::RenderWindow &window, sf::Time &deltaTime);
void Render(sf::RenderWindow &window);
void EventTriggered(sf::RenderWindow &window, sf::Event &event);
private:
sf::Sprite *_splashSprite;
};
最后我想创建一个新的 Splashscreen 对象并将地址分配给基址指针 class:
void Game::Init() {
Screen* ptrScreen = new Splashscreen;
_displayMgr.AddScreen("Splash", ptrScreen);
_displayMgr.ChangeScreen("Splash");
}
正如我之前提到的,我已经查过这个问题并找到了大量的解决方案,并提出了我现在所拥有的。但我仍然在行
中收到错误
Screen* ptrScreen = new Splashscreen;
编译时显示以下内容:
error: invalid new-expression of abstract class type 'Splashscreen'
我只是不明白这一点,因为我已经在此处定义了 Splashscreen.hpp 中提到的所有声明方法:
Splashscreen.cpp
#include "SplashScreen.hpp"
Splashscreen::Splashscreen() {}
Splashscreen::~Splashscreen() {}
void Splashscreen::Init() {}
void Splashscreen::Update(sf::RenderWindow &window, sf::Time &deltaTime) {}
void Splashscreen::Render(sf::RenderWindow &window) {}
void Splashscreen::EventTriggered(sf::RenderWindow &window, sf::Event &event) {}
我希望有人能帮助我并原谅我,如果这个问题已经很多次了。但是,当您从 Java 更改为 C++ 时,很难更改您的 "mind of programming"。但我已经更喜欢 C++ :) 它具有挑战性,我非常喜欢它。
[编辑]:
我只更改了以下内容:
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init() const;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const;
void Render(sf::RenderWindow &window) const;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const;
private:
sf::Sprite *_splashSprite;
};
其他还是一样
来自Screen
:
virtual void Init() const = 0;
来自Splashscreen
:
void Init();
其中一个是const
,另一个不是。您应该从 Screen
中删除 const
或将其添加到 Splashscreen
,以合适的为准。
Screen
中的所有纯虚函数都定义为 const
。这个尾随的 const
不仅表明函数不会修改对象,而且它完全是签名的一部分。
很遗憾,Screesplash
中的同名函数没有定义为const
。所以这些功能不是对你的纯虚拟的覆盖,而是额外的功能。这意味着您的纯虚函数仍然没有被覆盖,因此您的 Screensplash
仍然是一个无法实例化的抽象 class 。
要解决您的问题,只需在您的函数后面添加尾随 const
关键字。
为避免以后出现类似问题,请养成使用override
关键字告诉编译器你的意图的习惯。如果不小心你的签名不匹配,编译器会立即告诉你你的函数不是你想的重写。
class Splashscreen : public Screen {
public:
...
void Init() const override;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const override;
void Render(sf::RenderWindow &window) const override;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const override;
...
};
我已经查找了 2 个小时(主要是在此站点上)以了解我在使用 C++ 编码时遇到的问题。我有一个抽象基础 class,看起来像这样:
Screen.hpp
#include <SFML/Graphics.hpp>
class Screen {
public:
virtual ~Screen();
virtual void Init() const = 0;
virtual void Render(sf::RenderWindow &window) const = 0;
virtual void Update(sf::RenderWindow &window, sf::Time &deltaTime) const = 0;
virtual void EventTriggered(sf::RenderWindow &window, sf::Event &event) const = 0;
};
接下来我声明了一个 class 派生自基数 class:
Splashscreen.hpp
#include "Screen.hpp"
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init();
void Update(sf::RenderWindow &window, sf::Time &deltaTime);
void Render(sf::RenderWindow &window);
void EventTriggered(sf::RenderWindow &window, sf::Event &event);
private:
sf::Sprite *_splashSprite;
};
最后我想创建一个新的 Splashscreen 对象并将地址分配给基址指针 class:
void Game::Init() {
Screen* ptrScreen = new Splashscreen;
_displayMgr.AddScreen("Splash", ptrScreen);
_displayMgr.ChangeScreen("Splash");
}
正如我之前提到的,我已经查过这个问题并找到了大量的解决方案,并提出了我现在所拥有的。但我仍然在行
中收到错误Screen* ptrScreen = new Splashscreen;
编译时显示以下内容:
error: invalid new-expression of abstract class type 'Splashscreen'
我只是不明白这一点,因为我已经在此处定义了 Splashscreen.hpp 中提到的所有声明方法:
Splashscreen.cpp
#include "SplashScreen.hpp"
Splashscreen::Splashscreen() {}
Splashscreen::~Splashscreen() {}
void Splashscreen::Init() {}
void Splashscreen::Update(sf::RenderWindow &window, sf::Time &deltaTime) {}
void Splashscreen::Render(sf::RenderWindow &window) {}
void Splashscreen::EventTriggered(sf::RenderWindow &window, sf::Event &event) {}
我希望有人能帮助我并原谅我,如果这个问题已经很多次了。但是,当您从 Java 更改为 C++ 时,很难更改您的 "mind of programming"。但我已经更喜欢 C++ :) 它具有挑战性,我非常喜欢它。
[编辑]:
我只更改了以下内容:
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init() const;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const;
void Render(sf::RenderWindow &window) const;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const;
private:
sf::Sprite *_splashSprite;
};
其他还是一样
来自Screen
:
virtual void Init() const = 0;
来自Splashscreen
:
void Init();
其中一个是const
,另一个不是。您应该从 Screen
中删除 const
或将其添加到 Splashscreen
,以合适的为准。
Screen
中的所有纯虚函数都定义为 const
。这个尾随的 const
不仅表明函数不会修改对象,而且它完全是签名的一部分。
很遗憾,Screesplash
中的同名函数没有定义为const
。所以这些功能不是对你的纯虚拟的覆盖,而是额外的功能。这意味着您的纯虚函数仍然没有被覆盖,因此您的 Screensplash
仍然是一个无法实例化的抽象 class 。
要解决您的问题,只需在您的函数后面添加尾随 const
关键字。
为避免以后出现类似问题,请养成使用override
关键字告诉编译器你的意图的习惯。如果不小心你的签名不匹配,编译器会立即告诉你你的函数不是你想的重写。
class Splashscreen : public Screen {
public:
...
void Init() const override;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const override;
void Render(sf::RenderWindow &window) const override;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const override;
...
};