C++-虚拟继承
C++ - virtual inheritance
首先,我想说我最初是用C++初级读本学习C++的,但因为我想了解一些关于SDL库的知识,我决定从Shaun Mitchell那里获得"SDL游戏开发"一书。
现在是第3章,我在虚拟继承方面遇到了一些问题。我知道它是如何工作的,但在我的程序中找不到问题。
错误:
||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
C:UsersDocumentstest - Kopie (2)game.cpp||In member function 'void Game::render()':|
C:UsersDocumentstest - Kopie (2)game.cpp|78|error: no matching function for call to 'GameObject::draw(SDL_Renderer*&)'|
C:UsersDocumentstest - Kopie (2)game.cpp|78|note: candidate is:|
C:UsersDocumentstest - Kopie (2)GameObject.h|11|note: virtual void GameObject::draw()|
C:UsersDocumentstest - Kopie (2)GameObject.h|11|note: candidate expects 0 arguments, 1 provided|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
我知道我有太多的争论,但游戏对象有两个派生类,玩家类和敌人类。敌人类需要一个参数,但玩家类不需要。因此,当我删除参数时,生成器会给我更多的错误。
我会在这里列出所有代码:
game.h:
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#include <vector>
#include "Player.h"
using namespace std;
class Game
{
public:
bool init(const char* title, int xpos, int ypos, int width, int height, int flags);
void render();
void update();
void handleEvents();
void clean();
bool running() { return m_bRunning; }
SDL_Renderer* getRenderer() const { return m_pRenderer; }
std::vector<GameObject*> m_gameObjects;
static Game* Instance()
{
if(s_pInstance == 0)
{
s_pInstance = new Game();
return s_pInstance;
}
return s_pInstance;
}
private:
Game() {}
bool m_bRunning;
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
SDL_Texture* m_pTexture; // the new SDL_Texture variable
int m_currentFrame;
GameObject* m_go;
GameObject* m_player;
GameObject* m_enemy;
static Game* s_pInstance;
};
game.cpp:
#include <SDL.h>
#include <iostream>
#include "game.h"
#include <SDL_image.h>
#include <vector>
using namespace std;
bool Game::init(const char* title, int xpos, int ypos, int width,
int height, int flags)
{
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
m_gameObjects.push_back(new Player(new LoaderParams(100, 100, 128, 82, "animate")));
m_gameObjects.push_back(new Enemy(new LoaderParams(300, 300, 128, 82, "animate")));
cout << "SDL init successn";
// init the window
m_pWindow = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
if(m_pWindow != 0) // window init success
{
cout << "window creation successn";
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
if(m_pRenderer != 0) // renderer init success
{
cout << "renderer creation successn";
SDL_SetRenderDrawColor(m_pRenderer, 255,0,0,255);
if(!TextureManager::Instance()->load("explosion-sprite.png", "animate", m_pRenderer))
{
return false;
}
}
else
{
cout << "renderer init failn";
return false; // renderer init fail
}
}
else
{
cout << "window init failn";
return false; // window init fail
}
}
else
{
cout << "SDL init failn";
return false; // SDL init fail
}
cout << "init successn";
m_bRunning = true; // everything inited successfully,
return true;
}
void Game::render()
{
SDL_RenderClear(m_pRenderer); // clear the renderer to
for(std::vector<GameObject*>::size_type i = 0; i != m_gameObjects.size(); i++)
{
m_gameObjects[i]->draw(m_pRenderer);
}
SDL_RenderPresent(m_pRenderer); // draw to the screen
}
void Game::handleEvents(){
SDL_Event event;
if(SDL_PollEvent(&event)){
switch (event.type){
case SDL_QUIT:
m_bRunning = false;
break;
default:
break;
}
}
}
void Game::clean(){
cout << "cleaning gamen";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}
void Game::update()
{
for(std::vector<GameObject*>::size_type i = 0; i !=
m_gameObjects.size(); i++)
{
m_gameObjects[i]->update();
}
}
Game* Game::s_pInstance = 0;
TextureManager.h:
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#include <map>
#include "Loaderparams.h"
using namespace std;
class TextureManager{
public:
bool load(string filename, string id, SDL_Renderer* Renderer);
void draw(string id, int x, int y, int width, int height, SDL_Renderer* Renderer, SDL_RendererFlip = SDL_FLIP_NONE);
void drawFrame(string id, int x, int y, int width, int height, int row, int frame, SDL_Renderer* Renderer, SDL_RendererFlip flip = SDL_FLIP_NONE);
static TextureManager* Instance();
private:
TextureManager() {}
map<string, SDL_Texture*> textureMap;
};
TextureManager.cpp:
#include <SDL.h>
#include <iostream>
#include "TextureManager.h"
#include <SDL_image.h>
using namespace std;
bool TextureManager::load(string filename, string id, SDL_Renderer* Renderer){
SDL_Surface* surf = IMG_Load(filename.c_str());
if(surf == NULL)
return false;
SDL_Texture* text = SDL_CreateTextureFromSurface(Renderer, surf);
SDL_FreeSurface(surf);
if(text != 0){
textureMap[id] = text;
return true;
}
return false;
}
void TextureManager::draw(string id, int x, int y, int width, int height, SDL_Renderer* Renderer, SDL_RendererFlip flip){
SDL_Rect source;
SDL_Rect destination;
source.x = 0;
source.y = 0;
destination.w = source.w = width;
destination.h = source.h = height;
destination.x = x;
destination.y = y;
SDL_RenderCopyEx(Renderer, textureMap[id], &source, &destination, 0, 0, flip);
}
void TextureManager::drawFrame(string id, int x, int y, int width, int height, int row, int frame, SDL_Renderer* Renderer, SDL_RendererFlip flip){
SDL_Rect source;
SDL_Rect destination;
source.x = width * frame;
source.y = height * row;
destination.w = source.w = width;
destination.h = source.h = height;
destination.x = x;
destination.y = y;
SDL_RenderCopyEx(Renderer, textureMap[id], &source, &destination, 0, 0, flip);
}
TextureManager* s_pInstance = 0;
TextureManager* TextureManager::Instance(){
if(s_pInstance == 0){
s_pInstance = new TextureManager();
return s_pInstance;
}
return s_pInstance;
}
player.h:
#include "GameObject.h"
using namespace std;
class Player : public SDLGameObject
{
public:
Player(const LoaderParams* pParams): SDLGameObject(pParams){}
virtual void draw();
virtual void update();
virtual void clean();
};
// Enemy class
class Enemy : public SDLGameObject
{
public:
Enemy(const LoaderParams* pParams);
virtual void draw();
virtual void update();
virtual void clean();
};
player.cpp:
#include "Player.h"
using namespace std;
void Player::load(int x, int y, int width, int height, string textureID)
{
GameObject::load(x, y, width, height, textureID);
}
void Player::draw()
{
SDLGameObject::draw(); // we now use SDLGameObject
}
void Player::update()
{
m_x -= 1;
m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
}
void Player::clean() {}
//ENEMY
void Enemy::load(int x, int y, int width, int height, string
textureID)
{
GameObject::load(x, y, width, height, textureID);
}
void Enemy::draw(SDL_Renderer* pRenderer)
{
GameObject::draw(pRenderer);
}
void Enemy::update()
{
m_position.setX(m_position.getX() + 1);
m_position.setY(m_position.getY() + 1);
m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
}
void Enemy::clean(){
}
Gameobject.h:
#include <iostream>
#include <SDL.h>
#include "TextureManager.h"
#include "Vector2D.h"
using namespace std;
class GameObject
{
public:
virtual void draw() = 0;
virtual void update() = 0;
virtual void clean() = 0;
protected:
GameObject(const LoaderParams* pParams) {}
virtual ~GameObject() {}
};
class SDLGameObject : public GameObject
{
public:
SDLGameObject(const LoaderParams* pParams) :
GameObject(pParams), m_position(pParams->getX(), pParams->getY())
{
m_width = pParams->getWidth();
m_height = pParams->getHeight();
m_textureID = pParams->getTextureID();
m_currentRow = 1;
m_currentFrame = 1;
}
virtual void draw();
virtual void update();
virtual void clean();
protected:
Vector2D m_position;
int m_width;
int m_height;
int m_currentRow;
int m_currentFrame;
std::string m_textureID;
};
Gameobject.cpp:
#include <iostream>
#include <SDL.h>
#include "GameObject.h"
using namespace std;
void GameObject::draw(SDL_Renderer* pRenderer)
{
TextureManager::Instance()->drawFrame(m_textureID, m_x, m_y,
m_width, m_height, m_currentRow, m_currentFrame, pRenderer);
}
void GameObject::update()
{
m_x += 1;
}
void GameObject::clean(){
}
//SDLGameObject
void SDLGameObject::draw()
{
TextureManager::Instance()->drawFrame(m_textureID,
(int)m_position.getX(), (int)m_position.getY(), m_width,
m_height, m_currentRow, m_currentFrame,
Game::Instance()->getRenderer());
}
还有一个Vector.h,但它对问题来说并不重要
class GameObject
{
public:
virtual void draw() = 0;
virtual void update() = 0;
virtual void clean() = 0;
protected:
GameObject(const LoaderParams* pParams) {}
virtual ~GameObject() {}
};
只有draw()
所以你不能做m_gameObjects[i]->draw(m_pRenderer);
签名不匹配。GameObject
类只有一个draw()
。
请记住,不能通过继承来更改虚拟函数的函数签名。签名必须保持不变。
我想您也应该在头文件中添加重载的方法签名。
virtual void draw();
virtual void draw(SDL_Renderer* pRenderer);
我没有检查整个代码,所以可能还有其他问题,但那个特定的错误消息表明具有该签名的draw
方法不存在。
请记住,cpp
文件将被编译成对象文件,而链接器是知道该方法存在的人,这就是为什么没有任何关于该重载方法的信息的编译器抱怨签名不合适的原因。
我现在也关注这本书。这是本书第3章的结尾,其中GameObject
类被重构为抽象类,SDLGameObject
被引入为具有SDL
特定接口的子代。此外,Game类被重构为单例。出现此错误是因为在SDLGameObject
及其子代(Player, Enemy
)的新版本中,SDL
renderer
不再作为参数传递给它们的方法。相反,它是通过像Game::Instance()->getRenderer()
这样的Game单例对象访问的。即使进行了所有更改,动画图像也拒绝显示在窗口中!直到我发现没有人调用TextureManager
从文件中加载图像。我已经将新字段fileName
及其相应的getter添加到类LoaderParams
中,并将以下代码添加到SDLGameObject
类的构造函数中:
TextureManager::Instance()->load(pParams->getFileName(), m_textureID, TheGame::Instance()->getRenderer());
那些关注这本书的人要注意!
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 大小虚拟继承中的派生类
- 删除C++继承中虚拟类成员的代码重复
- 重写虚拟函数和继承
- C++ 多级虚拟继承编译问题
- 如何正确获得虚拟继承?
- 编译时继承类中的隐式虚拟与显式虚拟
- 钻石继承虚拟成员铸造与指针
- CPP 继承虚拟方法解析顺序
- 关于C 接口(纯虚拟类)/多重继承/虚拟继承的设计Qustion
- 继承虚拟类C 的派生类
- 多个继承/虚拟函数
- 不能从具有虚拟继承(C++虚拟继承)的类派生
- C++多重继承+虚拟函数(-歧义)=怪异行为(也是函数指针)
- 为什么我不能继承虚拟基的构造函数?
- C++继承虚拟函数崩溃
- c++多重继承/虚拟继承
- 派生类的成员函数是否从基类继承虚拟性?
- 继承虚拟函数的类的boost::optional失败的原因
- c++继承虚拟函数