This question already has answers here:
Virtual/pure virtual explained
(12 answers)
Closed 1 year ago.
booking.h
#ifndef _BOOKING_H_
#define _BOOKING_H_
#include <string>
class Event {
private:
std::string event_option;
public:
Event(std::string event_option);
virtual ~Event();
void list_specific_event_details();
virtual void list_details();
};
class Films : public Event {
private:
std::string movie_option;
public:
Films(std::string movie_option);
void list_details();
};
class Live_Music : public Event {
private:
std::string live_music_option;
public:
Live_Music(std::string live_music_option);
void list_details();
};
class Standup_Comedy : public Event {
private:
std::string comedy_option;
public:
Standup_Comedy(std::string comedy_option);
void list_details();
};
#endif
booking.cpp
#include "booking.h"
#include <string>
Event::Event(std::string event_option)
{
this->event_option = event_option;
}
Event::~Event()
{
}
void Event::list_specific_event_details()
{
return list_details();
}
Films::Films(std::string movie_option) : Event("Films")
{
this->movie_option = movie_option;
}
void Films::list_details()
{
//some code ...
return;
}
Live_Music::Live_Music(std::string live_music_option) : Event("Live_Music")
{
this->live_music_option = live_music_option;
}
void Live_Music::list_details()
{
//some code...
return;
}
Standup_Comedy::Standup_Comedy(std::string comedy_option) : Event("Standup_Comedy")
{
this->comedy_option = comedy_option;
}
void Standup_Comedy::list_details()
{
//some code...
return;
}
main.cpp
#include "booking.h"
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector <Event *> choice;
choice.push_back(new Films("f"));
choice.push_back(new Live_Music("l"));
choice.push_back(new Standup_Comedy("s"));
for(unsigned i = 0; i < choice.size(); i++)
{
choice[i] -> list_specific_event_details();
}
for (Event * e: choice) delete e;
choice.clear();
}
I have written the above block of codes and got an error when I tried to compile it.
The error is as follows:
usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccuWXzBM.o:booking.cpp:(.rdata$_ZTV5Event[_ZTV5Event]+0x20): undefined reference to `Event::list_details()'
collect2: error: ld returned 1 exit status
Why am I getting this error, and how can I solve it?
You have not defined your method Event::list_details(). If you only want to declare the function but do not want to implement it, that is what is called an Interface, you can make it a pure virtual method with:
class Event
{
...
virtual void list_details() = 0;
...
};
Related
I am using c++11 compiler.
I have two classes - class Test and class TestHelper.
The class Test is a friend-to-class TestHelper.
The class Test is only which we can access from outside.
Now, we want to call Test API i.e. setVal(). This setVal() should call
Test2 API i.e. setX and is expecting this pointer. I don't want to use this pointer but want
to use a smart pointer instead. How can I do so?
The notion of this kind of desirability is because of the fact that in reality, my class Test is pretty big. So, I am trying to make a helper class for Test i.e.
class TestHelper;
class Test
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(this, 324);
}
};
class TestHelper
{
public:
void setX(Test *test, int val) {
/** some algorithm here and then change val to something else */
test->x = val*100;
}
};
int main()
{
std::cout << "Hello World!\n";
Test x;
x.setVal(130);
}
I tried changing the prototype from void setX(Test *test, int val)
to void setX(std::shared_ptr<Test> test, int val) but don't know how to pass this pointer
as std::shared_ptr<Test> test here.
So here is working solution with shared pointers. The example doesn't even compile due to missing definitions so you have to restructure your code into headers and cpp files.
Test.h:
#ifndef TEST_H
#define TEST_H
#include <memory>
#include "TestHelper.h"
class Test : public std::enable_shared_from_this<Test>
{
private:
friend class TestHelper;
int x;
public:
void display();
void setVal(int val);
};
#endif
Test.cpp:
#include <iostream>
#include "Test.h"
void Test::display() {
std::cout << x;
}
void Test::setVal(int val) {
TestHelper testH;
testH.setX(shared_from_this(), 324);
}
TestHelper.h:
#ifndef TESTHELPER_H
#define TESTHELPER_H
class Test;
class TestHelper
{
public:
void setX(std::shared_ptr<Test> test, int val);
};
#endif
TestHelper.cpp:
#include <memory>
#include "TestHelper.h"
#include "Test.h"
void TestHelper::setX(std::shared_ptr<Test> test, int val) {
/** some algorithm here and then change val to something else */
test->x = val*100;
}
main.cpp:
#include <iostream>
#include <memory>
#include "Test.h"
int main(void){
std::cout << "Hello World!\n";
auto x = std::make_shared<Test>();
x->setVal(130);
x->display();
}
You can run it here: https://paiza.io/projects/e/79dehCx0RRAG4so-sVZcQw
I don't understand why you want this, here's a few variants that compile
reference
// Reference variant
#include <iostream>
class Test;
class TestHelper
{
public:
void setX(Test & test, int val);
};
class Test
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(*this, 324);
}
};
void TestHelper::setX(Test &test, int val)
{
/** some algorithm here and then change val to something else */
test.x = val*100;
}
int main()
{
Test x;
x.setVal(130);
x.display();
}
http://cpp.sh/7t3ec
shared ptr
// Shared ptr variant
#include <iostream>
#include <memory> // Required for shared_ptrs
class Test;
class TestHelper
{
public:
void setX(std::shared_ptr<Test> test, int val);
};
class Test : public std::enable_shared_from_this<Test>
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(shared_from_this(), 324);
}
};
void TestHelper::setX(std::shared_ptr<Test> test, int val)
{
/** some algorithm here and then change val to something else */
test->x = val*100;
}
int main()
{
auto x = std::make_shared<Test>(); // x needs to be created as shared_ptr or it won't work
x->setVal(130);
x->display();
}
http://cpp.sh/87ao2
Perhaps with these you can refine your question?
Hello i have problem of compile my code
i follow http://gamedevgeek.com/tutorials/managing-game-states-in-c/ tutorial
but it fail to compile and i don't know why.
the error msg from visual studio
here is my code
the CGameEngine modify code
#include <vector>
#include "GameState.h"
#include "GameEngine.h"
class GameState;
class GameStateManager
{
public:
GameStateManager(GameEngine* engine, MSG * msg);
~GameStateManager();
void Cleanup();
void ChangeState(GameState* state);
void Update();
bool Running() { return m_running; }
void Quit();
private:
std::vector<GameState *> states;
bool m_running;
GameEngine * m_engine;
MSG *m_msg;
};
#include "GameStateManager.h"
GameStateManager::GameStateManager(GameEngine* engine, MSG * msg)
:m_engine{ engine }, m_msg{ msg }, m_running{ true }
{
}
GameStateManager::~GameStateManager()
{
}
void GameStateManager::Cleanup()
{
while (!states.empty()) {
states.back()->Exit();
states.pop_back();
}
}
void GameStateManager::Quit()
{
m_running = false;
m_msg->message = WM_QUIT;
}
void GameStateManager::ChangeState(GameState* state)
{
if (!states.empty()) {
states.back()->Exit();
states.pop_back();
}
states.push_back(state);
states.back()->Enter(m_engine, m_msg);
}
void GameStateManager::Update()
{
states.back()->Update(this);
}
the CGameState modify code
#include "GameStateManager.h"
class GameState
{
public:
GameState() {}
virtual ~GameState() {}
virtual void Enter(GameEngine * , MSG * ) = 0;
virtual void Update(GameStateManager* game) =0;
virtual void Exit() = 0;
};
one of the state class
#include "MainMenu.h"
class Logo :public GameState
{
public:
Logo();
~Logo();
static Logo* Instance()
{
return &m_Logo;
}
void Enter(GameEngine * engine, MSG * msg);
void Update(GameStateManager* game);
void Exit();
private:
static Logo m_Logo;
};
#include "Logo.h"
Logo::Logo()
{
}
Logo::~Logo()
{
}
void Logo::Enter(GameEngine * engine, MSG * msg)
{
m_GameEngine_Info = engine;
m_msg = msg;
}
void Logo::Update(GameStateManager* game)
{
}
void Logo::Exit()
{
}
i get no compile error when editing the code, but when i try compile it get this error.
You have circular includes. Use include guards and replace
#include "GameStateManager.h"
with
class GameStateManager;
in GameState.h. Move this include into GameState.cpp.
Do similar with #include "GameEngine.h" and #include "GameState.h" in GameStateManager.h and GameStateManager.cpp.
This is my enum header file
//use like PostionType::President
enum PositionType
{ President,
VicePresident,
Secretary,
Treasurer,
Normal
};
And in my Ballot paper header and cpp file
#include <list>
#include <iostream>
#include "Candidate.h"
#include "PositionType.h" //include enum
class BallotPaper
{
private:
PositionType _positionbp;
std::list<Candidate> _candidatesbp;
public:
BallotPaper();
void setPositionBP(PositionType positionbp);
PositionType getPositionBP();
void setCandidateBP(std::list<Candidate> candidatesbp);
std::list<Candidate> getCandidateBP();
Candidate getCandidate(int index);
void ShowCandidates();
~BallotPaper();
};
#include "BallotPaper.h"
#include <string>
#include <iostream>
void BallotPaper::setPositionBP(PositionType positionbp)
{
_positionbp = positionbp;
}
PositionType BallotPaper::getPositionBP()
{
return _positionbp;
}
void BallotPaper::setCandidateBP(std::list<Candidate> candidatesbp)
{
_candidatesbp = candidatesbp;
}
std::list<Candidate> BallotPaper::getCandidateBP()
{
return _candidatesbp;
}
void BallotPaper::ShowCandidates()
{
for(Candidate c : _candidatesbp)
{
c->IncreaseVoteCount(); //ERROR!!!!
}
}
and this will be my candidate header and cpp file
class Candidate:public Member
{
private:
int _votecount;
PositionType _position;
public:
Candidate(std::string name, int id, std::string course, int contact, std::string joindate, PositionType currentposition) ;
~Candidate();
void setVoteCount(int votecount);
int getVoteCount();
void setPosition(PositionType position);
PositionType getPosition();
void IncreaseVoteCount(); //increase _votecount
};
#include "Candidate.h"
Candidate::Candidate()
{
_votecount = 0;
}
void Candidate::setVoteCount(int votecount)
{
_votecount = votecount;
}
int Candidate::getVoteCount()
{
return _votecount;
}
void Candidate::setPosition(PositionType position)
{
_position = position;
}
PositionType Candidate::getPosition()
{
return _position;
}
void Candidate::IncreaseVoteCount()
{
_votecount++;
}
I know is a super long code, and I appreciate for your patience in looking through it. My error is that it seems that it cannot recognize the function of "IncreaseVoteCount" in 'Candidate c'.
I have try to double check the syntax and the code for multiple times but i still don't understand what is the error here.
Sorry for the lack of a descriptive title.
I'm getting an error "one or more multiply defined symbols found"; to be more specific, I'm getting 46 of them. One for each function in my header/source files. Using Visual Studios 2013.
Here is the relevant source code:
augments.h
#ifndef AUGMENTS_H_
#define AUGMENTS_H_
namespace Augments {
// only used for pass-ins for constructors
enum class Weapon_Type {
sword
};
enum class Head_Type {
head
};
enum class Body_Type {
body
};
// the player (Monster) has a head, body and weapon
// that augments his abilities. This will mostly
// be the thing that draws to the screen for each
// augmentation, but more importantly it contains
// specific statistics about each one.
// So if there was a body that was able to fly,
// there would be a bool that denotes this ability.
class Head : public Actor {
const Head_Type type;
public:
Head(Head_Type);
void Update(float dt);
};
class Body : public Actor {
const Body_Type type;
public:
Body(Body_Type);
void Update(float dt);
};
class Weapon : public Actor {
const Weapon_Type type;
public:
Weapon(Weapon_Type);
void Update(float dt);
};
}
using AugHead = Augments::Head;
using AugBody = Augments::Body;
using AugWep = Augments::Weapon;
#endif
augments.cpp
#include "stdafx.h"
#include "Angel.h"
#include "Augments.h"
#include "LD33.h"
Augments::Head::Head(Augments::Head_Type x) : type(x) {
switch ( x ) {
case Head_Type::head:
SetSprite("Images\\head.png");
break;
};
};
void Augments::Head::Update(float dt) {
SetPosition(Game::thePlayer->GetPosition().X,
Game::thePlayer->GetPosition().Y-
MathUtil::ScreenToWorld(Vec2i(0,40)).Y);
};
Augments::Body::Body(Augments::Body_Type x) : type(x) {
switch ( x ) {
case Body_Type::body:
SetSprite("Images\\body.png");
break;
};
}
void Augments::Body::Update(float dt) {
SetPosition(Game::thePlayer->GetPosition().X,
Game::thePlayer->GetPosition().Y);
}
Augments::Weapon::Weapon(Augments::Weapon_Type x ) : type(x) {
switch ( x ) {
case Weapon_Type::sword:
SetSprite("Images\\weapon.png");
break;
}
}
void Augments::Weapon::Update(float dt) {
SetPosition(Game::thePlayer->GetPosition().X,
Game::thePlayer->GetPosition().Y-
MathUtil::ScreenToWorld(Vec2i(0,-40)).Y);
}
monster.h
// monster related
#include "Augments.h"
#include "Angel.h"
#ifndef MONSTER_H_
#define MONSTER_H_
namespace Player {
// contains information like health attack etc
// but more important body types
class Monster : public PhysicsActor {
int max_health, curr_health;
int attack_damage;
Augments::Head* frame_head;
Augments::Weapon* frame_weapon;
Augments::Body* frame_body;
public:
void Refresh(float dt);
int R_Max_Health() const;
int R_Curr_Health() const;
int R_Attack_Damage() const;
Augments::Head* R_Frame_Head();
Augments::Weapon* R_Frame_Weapon();
Augments::Body* R_Frame_Body();
void Set_Max_Health(int);
void Set_Curr_Health(int);
void Add_Curr_Health(int);
void Set_Attack_Damage(int);
// will automatically remove old
// actors from the stage and deallocate
void Set_Frame_Head(Augments::Head_Type);
void Set_Frame_Weapon(Augments::Weapon_Type);
void Set_Frame_Body(Augments::Body_Type);
Monster(Augments::Head_Type,
Augments::Weapon_Type,
Augments::Body_Type);
};
};
using PlMonster = Player::Monster;
#endif
monster.cpp
#include "stdafx.h"
#include "Monster.h"
#include "Augments.h"
#include "Angel.h"
void Player::Monster::Refresh(float dt) {
};
int Player::Monster::R_Max_Health() const { return max_health; }
int Player::Monster::R_Curr_Health() const { return curr_health; }
int Player::Monster::R_Attack_Damage() const { return attack_damage; }
Augments::Head* Player::Monster::R_Frame_Head() { return frame_head; }
Augments::Body* Player::Monster::R_Frame_Body() { return frame_body; }
Augments::Weapon* Player::Monster::R_Frame_Weapon() { return frame_weapon; }
void Player::Monster::Set_Max_Health(int x) { max_health = x; }
void Player::Monster::Set_Curr_Health(int x) { curr_health = x; }
void Player::Monster::Add_Curr_Health(int x) { curr_health += x; }
void Player::Monster::Set_Attack_Damage(int x) { attack_damage = x; }
void Player::Monster::Set_Frame_Head(Augments::Head_Type x) {
if ( frame_head != nullptr ) {
frame_head->Destroy();
delete frame_head;
frame_head = nullptr;
}
frame_head = new Augments::Head(x);
theWorld.Add(frame_head);
};
void Player::Monster::Set_Frame_Weapon(Augments::Weapon_Type x) {
if ( frame_weapon != nullptr ) {
theWorld.Remove(frame_weapon);
delete frame_weapon;
frame_weapon = nullptr;
}
frame_weapon = new Augments::Weapon(x);
theWorld.Add(frame_weapon);
};
void Player::Monster::Set_Frame_Body(Augments::Body_Type x) {
if ( frame_body != nullptr ) {
theWorld.Remove(frame_body);
delete frame_body;
frame_body = nullptr;
}
frame_body = new Augments::Body(x);
theWorld.Add(frame_body);
};
Player::Monster::Monster(Augments::Head_Type head,
Augments::Weapon_Type weapon,
Augments::Body_Type body) {
frame_body = nullptr;
frame_head = nullptr;
frame_weapon = nullptr;
Set_Frame_Body(body);
Set_Frame_Head(head);
Set_Frame_Weapon(weapon);
}
source.cpp
#include "stdafx.h"
#include "LD33.h"
#include "Angel.h"
int main ( ) {
Game::Initialize();
theWorld.StartGame();
theWorld.Destroy();
return 0;
}
Errors include things such as:
Error 43 error LNK2005: "public: int __thiscall Player::Monster::R_Attack_Damage(void)const " (?R_Attack_Damage#Monster#Player##QBEHXZ) already defined in Augments.obj C:\Users\The Shire\Desktop\ludum_dare\ludumdare33\Code\ClientGame\source.obj ClientGame
Error 3 error LNK2005: "public: void __thiscall Player::Monster::Set_Frame_Body(enum Augments::Body_Type)" (?Set_Frame_Body#Monster#Player##QAEXW4Body_Type#Augments###Z) already defined in Augments.obj C:\Users\The Shire\Desktop\ludum_dare\ludumdare33\Code\ClientGame\LD33.obj ClientGame
And it pretty much states similar for every single function in Monster.
Sorry for just dumping a ton of code. I've been trying to debug it for awhile but couldn't come up with any reasonable solution. I have the include guards, I don't see any namespace conflicts, and everything that needs to be defined is outside of the header files. I can't find anything in augments.h that would be causing this. I also thought it might be the enums, but replacing them with just int did not work either.
I'm thinking it might be the order of the include files? hmm. Maybe there's somehow multiple source files somewhere but I would have no clue as to how. Any help?
Had included Monster.cpp in another header file on accident! Oops
I am completing my c++/CLI wrapper for the following native c++ class:
#ifndef __TV3DENGINE_H__
#define __TV3DENGINE_H__
#pragma once
#include "TV3DMoteur.h"
#include "Input.h"
#include "Area.h"
#include <vcclr.h>
class Engine3D
{
public:
CLTV3DMoteur* clTV3D;
CLInput* clInput;
CLArea* clArea;
CLGlobalVar * clGlobalVar;
Engine3D();
~Engine3D();
void Setup(HWND TVScreenHWND, string PathString);
void UpdateLoop();
void Cleanup();
bool AppStillIdle();
CLTV3DMoteur* GetTV3D();
CLInput* GetInput();
CLArea* GetArea();
CLGlobalVar * GetGlobalVar();
};
#endif
The actual constructor for Engine3D is :
Engine3D::Engine3D()
{
clTV3D = CLTV3DMoteur::getInstance();
clInput = CLInput::getInstance();
clArea = CLArea::getInstance();
clGlobalVar = CLGlobalVar::getInstance();
}
Here is the actual wrapper:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper() { m_nativeClass = new Engine3D(); }
~Engine3DWrapper() { delete m_nativeClass; }
void Setup(System::IntPtr tvscreen, System::String^ AppPath) {
System::String^ managedPath = AppPath;
m_nativeClass->Setup((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(managedPath));
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
My question is how can I modifiy my Wrapper so I can have access to, exemple, Engine3DWrapper->clGlobalVar->BLABLABLA() where BLABLABLA would be all the different methods defined in the CLGlobalVar c++singleton?
I tried via this technique :
property String ^Name
{
String ^get()
{
return gcnew String(_stu->getName());
}
}
but that seems not possible since I need not to return a defined type.
thanks for your help.
Problem solved.
Here is the corrected Wrapper following Rufflewind suggestion:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper(System::IntPtr tvscreen, System::String^ AppPath)
{
m_nativeClass = new Engine3D((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(AppPath));
m_TV3D = m_nativeClass->GetTV3D();
m_Input = m_nativeClass->GetInput();
m_Area = m_nativeClass->GetArea();
m_GlobalVar = m_nativeClass->GetGlobalVar();
}
~Engine3DWrapper() {
delete m_nativeClass;
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
CLTV3DMoteur* m_TV3D;
CLInput* m_Input;
CLArea* m_Area;
CLGlobalVar* m_GlobalVar;
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
using simple Get Method in the native class:
CLGlobalVar *Engine3D::GetGlobalVar()
{
clGlobalVar = CLGlobalVar::getInstance();
return(clGlobalVar);
}
Thanks for you help!