Say I have these two classes:
class Object {
public:
virtual void update();
};
class Actor : public Object {
public:
void update();
}
Also assume that I am creating instances of the actor class as follows:
class somethingElse {
public:
void init();
std::vector<Object*> objects;
}
void somethingElse::init()
{
Actor tmp;
Object * tmpo = &tmp;
objects.push_back(tmpo);
}
I later iterate through objects:
for (int i = 0; i < objects.size(); i++)
objects.at(i)->update();
Placing a breakpoint at the two versions of update() revealed that the one being called is the one from the object class, and not the one from the actor class. Why is this, and is there any way around this problem?
In somethingElse::init() Actor tmp will go out of scope and be destroyed. The pointer will point to an object that no longer exists.
new could help here, but it would be safer to use a smart pointer, such as std::shared_ptr for example:
#include <iostream>
#include <vector>
#include <memory>
class Object {
public:
virtual void update() { std::cout << "Object update()\n"; }
virtual ~Object() = default;
};
class Actor : public Object {
public:
void update() { std::cout << "Actor update()\n"; }
};
class somethingElse {
public:
void init();
std::vector<std::shared_ptr<Object>> objects;
};
void somethingElse::init()
{
//Actor tmp;
auto tmpo = std::make_shared<Actor>();
//Object * tmpo = &tmp;
objects.push_back(tmpo);
}
int main()
{
somethingElse objs;
objs.init();
auto& objects = objs.objects;
for(int i = 0; i < objects.size(); i++)
objects.at(i)->update();
}
Related
I want an attribute in a C++ class be an uninstantiated class from a particular class heirachy. All members of this class heirachy would then implement the same method, meaning I could instantiate the object and then use the method when the situation calls for it. Here's some code (that doesn't compile) demonstrating what I mean:
#include <iostream>
using namespace std;
class Event {
public:
Event() = default;
virtual void go() = 0;
};
class EventA : Event {
public:
EventA() = default;
void go(){
cout << "Running event A"<< endl;
}
};
class EventB : Event {
public:
EventB() = default;
void go(){
cout << "Running event B"<< endl;
}
};
class Situation{
private:
Event* current_event = &EventA; //Problematic code: EventA does not refer to a value
public:
Situation() = default;
void setEvent(Event* event){
current_event = event;
}
void runEvent(){
current_event.go();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&EventB);
situation.runEvent();
return 0;
};
No, you cannot form pointers to classes, and you cannot invoke [non-static] member functions without a class instance (object).
You should probably std::make_unique an instance of the type you want to use.
Don't forget to give your base a virtual destructor, since you're doing polymorphism things.
A static alternative would be std::variant.
In two places, you seem to be doing what could be described as trying to take a pointer from a type:
Event* current_event = &EventA;
and
situation.setEvent(&EventB);
This doesn't work and is not really a thing with proper meaning in C++. What you are trying to do could be implemented in 3 different ways I can think of.
Method 1: instead of having a class, you can have a function pointer, and pass the function pointer as parameter:
#include <iostream>
using namespace std;
void eventA_go(){
cout << "Running event A"<< endl;
}
void eventB_go(){
cout << "Running event B"<< endl;
}
class Situation{
private:
using EventFunctionPtr = void (*)();
EventFunctionPtr current_event = &eventA_go;
public:
Situation() = default;
void setEvent(EventFunctionPtr event){
current_event = event;
}
void runEvent(){
current_event();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&eventB_go);
situation.runEvent();
return 0;
};
Method 2: you can make this code a little more generic, by allowing any type of callable in your Situation class, not only function pointers:
#include <iostream>
#include <functional>
using namespace std;
void eventA_go(){
cout << "Running event A"<< endl;
}
void eventB_go(){
cout << "Running event B"<< endl;
}
class Situation{
private:
std::function<void ()> current_event = eventA_go;
public:
Situation() = default;
template <typename F>
void setEvent(F&& event){
current_event = event;
}
void runEvent(){
current_event();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&eventB_go);
situation.runEvent();
return 0;
};
Method 3: you can go back to your original idea of having a base class that must be implemented to provide a go() method, but in this case you will actually have to make sure the objects you are calling do exists. A possible way to do it is with std::unique_ptr:
#include <iostream>
#include <memory>
using namespace std;
class Event {
public:
Event() = default;
virtual ~Event() = default;
virtual void go() = 0;
};
class EventA : public Event {
public:
EventA() = default;
void go(){
cout << "Running event A"<< endl;
}
};
class EventB : public Event {
public:
EventB() = default;
void go(){
cout << "Running event B"<< endl;
}
};
class Situation{
private:
std::unique_ptr<Event> current_event = std::make_unique<EventA>();
public:
Situation() = default;
void setEvent(std::unique_ptr<Event>&& event){
current_event = std::move(event);
}
void runEvent(){
current_event->go();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(std::make_unique<EventB>());
situation.runEvent();
return 0;
};
Notice that, in this case, the destructor of the abstract class must be virtual, and the inheritance must be public.
You seem to be confused about classes and variables. Which object would situation.runEvent(); run on? I think you want to publicly derive the classes from Event and initialize current_event when you need to. You don't need to do anything like current_event = &EventB. C++ automagically determines which function is needed to be called based on what current_event is dynamically pointing to. Here's what I think you meant to do:
#include <cassert>
#include <iostream>
class Event {
public:
virtual void go() = 0;
virtual ~Event() = default; // Don't forget the virtual destructor
};
class EventA : public Event {
public:
void go() override { std::cout << "Running event A" << std::endl; }
};
class EventB : public Event {
public:
void go() override { std::cout << "Running event B" << std::endl; }
};
class Situation {
private:
Event* current_event = nullptr;
public:
void setEvent(Event* event) { current_event = event; }
void runEvent() {
assert(current_event);
current_event->go();
}
};
int main() {
Situation situation;
EventA a;
EventB b;
situation.setEvent(&a);
situation.runEvent();
situation.setEvent(&b);
situation.runEvent();
}
I created:
class CMap:{
public
std::deque<CObject*> obiekty;
}
class CBullet{
public:
int damage;
}
and I added different type of element ( e.g. CTank, CBullet...)
and I want change atributes using deque
for( size_t i=0; i<game->Mapa->obiekty.size(); i++){
if(typeid(*(game->Mapa->obiekty[i]))==typeid(CBullet)){
this->HP=this->HP - game->Mapa->obiekty[i] (?? my problem/I can't do it ?? ->damage);
}
}
At first you need to inherit your derivate classes(CBullet, CTank) from base class (CObject), like this
//Base clase
class CObject
{
public:
//...
virtual ~CObject(){}; // Don't forget about virtual desctructor
};
class CBullet: public CObject
{
public:
//...
~CBullet(){};
void DoBulletMethod(){};
};
class CTank: public CObject
{
public:
//...
~CTank(){};
void DoTankMethod(){};
};
Then you can check all objects by dynamic_cast, like this:
for( size_t i=0; i< game->Mapa->obiekty.size(); i++)
{
if(dynamic_cast<CBullet*>(game->Mapa->obiekty[i]) != nullptr)
{
CBullet * BulletObj = dynamic_cast<CBullet*>(game->Mapa->obiekty[i]);
BulletObj->DoBulletMethod();
}
else if(dynamic_cast<CTank*>(game->Mapa->obiekty[i]) != nullptr)
{
CTank * TankObj = dynamic_cast<CTank*>(game->Mapa->obiekty[i]);
TankObj->DoTankMethod();
}
}
Or you can use polymorphism and create virtual methods, without further detection of current object type, for example create one virtual method in base class and override it in derivate classes:
//Base clase
class CObject
{
public:
//...
virtual ~CObject(){}; // Don't forget about virtual desctructor
virtual void DoActionInLoop()
{
//No action in base class
}
};
class CBullet: public CObject
{
public:
//...
~CBullet(){};
virtual void DoActionInLoop() override
{
std::cout << "I am bullet I can do here my tasks" << std::endl;
}
};
class CTank: public CObject
{
public:
//...
~CTank(){};
virtual void DoActionInLoop() override
{
std::cout << "I am tank and I can do here my tasks" << std::endl;
}
};
Then just call this method on each CObject* instance and get your polymorphism:
for( size_t i=0; i< game->Mapa->obiekty.size(); i++)
{
game->Mapa->obiekty[i]->DoActionInLoop();
}
Card game; I'm using abstract class for the "hands" which hold cards. The "hands" need to be slightly different but they share majority of the functions. So there is a Hand and a MasterHand which will inherit from the Hand and have an additional function. Everything goes through the deck which deals cards. My aim is to formulate the function within the Hand class in a way which allows writing into handV of the instance of the Abstract class that is called- regardless of it being Hand of MasterHand.. I've tried different methods but couldn't make any of them work.
class AbstractClass
{
virtual ~AbstractClass(){}
virtual void getCard(Card::card)=0 ;
};
class Hand:public AbstractClass
{
public:
vector<Card::card> handV;
virtual void getCard(Card::card k) override
{
writeIntoVector(k);
}
void writeIntoArray(Card::card g)
{
handV.push_back(g);
}
};
class HandMaster:public Hand
{
public:
vector<Card::card> handV;
// now here I would like to use the functions from Hand, but make them write into HandMaster.handV rather than Hand.handV
};
class Deck
{
void passCard(AbstractBase &x)
{
x.getCard(deck.back());
}
};
int main
{
AbstractBase* k=&h;
Hand* p = static_cast<Hand*>(k); // so I was trying to do it via casting in different convoluted ways but failed
MasterHand h2;
AbstractBase* m=&h2;
d.passCard(*k); // here I'd like the card to be passed to Hand.handV
d.passCard(*m); // here I'd like the card to be passed to MasterHand.handV
}
I added and simplified some of the code. But I will point you to some resources on polymorphism to get you started. I also remove the AbstractClass entirely since from an OOP perspective, you have objects that are Hands and another Master hand object.
https://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm
#include <vector>
#include <iostream>
//dummy class
struct Card{
int x;
};
class Hand{
public:
Hand(){}
std::vector<Card> handV;
virtual ~Hand(){}
virtual void getCard(Card k)
{
handV.push_back(k);
}
virtual void showHand()
{
for(std::vector<Card>::const_iterator it = handV.begin();
it != handV.end();
it++)
std::cout << it->x << " ";
}
};
class HandMaster: public Hand
{
public:
HandMaster(){}
//add additional methods
};
class HandOther: public Hand
{
public:
HandOther(){}
//add additional methods
};
class Deck
{
public:
std::vector<Card> deck;
Deck(){
Card c;
for(int i = 1; i <= 52; ++i){
c.x = i;
deck.push_back(c);
}
}
void passCard(Hand *x)
{
x->getCard(deck.back());
deck.pop_back();
}
};
int main()
{
Deck d;
Hand* p = new Hand();
HandMaster *m = new HandMaster();
HandOther * o = new HandOther();
for(int i =0; i < 5; ++i){
d.passCard(p);
d.passCard(m);
d.passCard(o);
}
std::cout << "\nHand:";
p->showHand();
std::cout << "\nHandMaster:";
m->showHand();
std::cout << "\nHandOther:";
o->showHand();
std::cout << "\n";
delete o;
delete p;
delete m;
}
I am trying to wrap my head around using a manager object to loop through the objects in an array and invoke the virtual functions for each object. Here is my code so far, thanks to some very helpful suggestions, it compiles but still doesn't make use of polymorphism the way that I want it to. Thanks in advance for any tips that can point me in the right direction.
#include <iostream>
class avian{
private:
static const int max_birds = 25;
avian* birds[max_birds];
int num_birds;
public:
avian() : num_birds(0){}
virtual ~avian() {
for (int i = 0; i < num_birds; ++i) { delete birds[i]; }
}
bool add(avian* b){
if (num_birds >= max_birds){ return false; }
birds[num_birds++] = b;
return true;
}
void make_bird(){
for (int i = 0; i< num_birds; ++i){birds[i]->make_bird();
}
}
virtual void lay_eggs(){} ;
virtual void bird_noise(){} ;
};
class turkey : public avian{
public:
void lay_eggs() const{ std::cout << "000\n"; }
void bird_noise() const { std::cout << "Gobble Gobble Gobble!\n"; }
};
class chicken : public avian {
public:
void lay_eggs() const { std::cout << "OOOOO\n"; }
void bird_noise() const { std::cout << "Bock Bock Bock!\n"; }
};
class quail : public avian{
public:
void lay_eggs() const { std::cout << "ooooooooo\n"; }
void bird_noise() const { std::cout << "Chirr Chirr Chirr!\n"; }
};
int main(){
avian* my_turkey = new turkey;
my_turkey->make_bird();
my_turkey->lay_eggs();
my_turkey->bird_noise();
delete my_turkey;
return 0;
}
You don't have a virtual base class destructor:
virtual ~avian() { ... }
Calls to delete pointer_to_avian will will call avian::~avian, but they will not propagate to the destructors of derived classes - UB, as compiler says.
avian::lay_eggs is declared, but not defined. Did you mean to make it pure virtual function? You've overriden it in every derived class.
avian::bird_noise - same as above
You forgot to delete my_turkey in main - you're leaking memory.
Your base virtual methods are not marked as const. But methods in derived classes are const. So they are not overriden.
Rule of thumb is to use override keyword in order to avoid such errors
I'm still fairly new to C++ and inheritance has gotten me in a pickle.
I know this works in C# since I'm always using Base.();
I'm hoping to be able to call a vector array of PlayerCharacter, derived from Entity.
Currently when I call it, it only calls Entity's update method.
int main()
{
vector<Entity*> list;
list.push_back(&PlayerCharacter());
for(int i = 0; i < list.size(); i++)
{
list[0]->Update();
}
}
class Entity
{
public:
Entity(void);
~Entity(void);
int hitpoints;
virtual void Update(void);
};
void Entity::Update(void)
{
int a = 0;
a++;
}
class PlayerCharacter : public Entity
{
public:
PlayerCharacter(void);
~PlayerCharacter(void);
bool Move();
void Update() override;
};
void PlayerCharacter::Update(void)
{
int a = 0;
a--;
}
list.push_back(&PlayerCharacter()); i think this is undefined behavior in your code.
In your case you should allocate the data on the heap like this: list.push_back( new PlayerCharacter() ); otherwise if you do this &PlayerCharacter() then the PlayerCharacter variable will be destroyed immediately and the pointer inside the list will point to garbage bytes.
Also to track which function is called you can use the debugger or print something in the console from each Update function.
This Works :
Few changes though : 1) You dont need to put Override 2) Definition of Constructor and destructor once declared 3) Created object of derived class and passed it to the list.
Output is : Inside PlayerCharacter
If you want to call base class update method method remove the volatile keyword. Or use base class pointer pointing to base class object.
class Entity
{
public:
Entity();
~Entity();
int hitpoints;
virtual void Update(void);
};
Entity::Entity()
{
}
Entity::~Entity()
{
}
void Entity::Update(void)
{
std::cout << " Inside Entity" <<std::endl;
int a = 0;
a++;
}
class PlayerCharacter : public Entity
{
public:
PlayerCharacter();
~PlayerCharacter();
bool Move();
void Update();
};
void PlayerCharacter::Update(void)
{
std::cout << " Inside PlayerCharacter" <<std::endl;
int a = 0;
a--;
}
PlayerCharacter::PlayerCharacter()
{
}
PlayerCharacter::~PlayerCharacter()
{
}
int main()
{
vector<Entity*> list;
PlayerCharacter ObjPlayerCharacter;
list.push_back(&ObjPlayerCharacter );
for(unsigned int i = 0; i < list.size(); i++)
{
list[0]->Update();
}
}