My question is related to C++. I have two families of classes: "Floor" and "Object". The first and the second family has a virtual method named "Enter" (which is called when an object enters the floor).
I wish to distinguish the behavior of "Enter" based on the sub-class of a "Floor" and "Object" respectively.
So I overload the method "Enter" with derived classes as the parameters. I have got code that works correctly, but requires two steps to call proper method, and would like to ask whether it can be done in one function call:
Edit: I updated the code (now full working example) with the potential solution. I have used a pointer to method with casting to retrieve proper overloaded method. This pointer is initialized in the constructors of the derived "Floor" classes.
#include <iostream>
using namespace std;
class Floor;
class Flagstone;
class Object
{
public:
virtual void Enter(Floor *f); /* Generic object enters generic floor */
virtual void Enter(Flagstone *fs); /* Generic object enters flagstone */
};
class Box : public Object
{
public:
void Enter(Floor *f);
void Enter(Flagstone *fs);
};
class Floor
{
public:
typedef void (Object::*enterPtr)(Floor *);
enterPtr enter; /* Pointer to method, initialized by constructor */
Floor(enterPtr enter) : enter(enter)
{
}
};
class Flagstone : public Floor
{
public:
/* Select proper overloaded function using casting */
Flagstone() : Floor((enterPtr)(void (Object:: *)(Flagstone *))&Object::Enter)
{
}
};
void Object::Enter(Floor *f)
{
cout << " Generic object enters generic floor" << endl;
}
void Object::Enter(Flagstone *fs)
{
cout << "Generic object enters flagstone" << endl;
}
void Box::Enter(Floor *f)
{
/* Box enters generic floor */
cout << "Box enters generic floor" << endl;
}
void Box::Enter(Flagstone *b)
{
/* Executed when a Box enters Flagstone: Correct */
cout << "Box enters Flagstone" << endl;
}
int main()
{
Floor *f = new Flagstone();
Object *o = new Box();
(o->*(f->enter))(f);
return 0;
}
Could I ask you to provide a minimum, reproducible example? Copying the code as is doesn't compile; indeed, there seems to be a circular dependency between the Floor and Object classes, as both rely on each other's implementation to be defined at all!
Both me and Nathan have tried to resolve this by forward-declaring the derived subtype 'Box', but this might be moot because:
you may want to invoke Box methods from Floor::Enter and Flagstone::Enter
the compiler throws an error for 'an undefined reference to a vtable', with answers here:
I agree with the others that Object::Enter(Flagstone*) seems redundant seems redundant given there exists Object::Enter(Floor*), which can resolve the dynamic type of the pointer passed-in
I ended up just realizing that the main() in this code could be actually a virtual Object or Floor method! Proper method will be called at first place and it will know one of the objects' true class.
So I cleaned the code. The function Enter(Floor *, Item *) just calls virtual method Floor::Enter() and it delegates the control to virtual method Item::Enter(), but now with addition to overloading.
The result method just reacts for the specific Floor and Item for example: Flagstone and Box incrementing the placed boxes counter.
This is very clean solution, however I can't make the methods inline as there is a cycle dependancy. But it's not a problem.
Here is the solution code:
#include <iostream>
using namespace std;
class Floor;
class Flagstone;
class Item
{
public:
/* Overload */
virtual void Enter(Floor *fl)
{
cout << "Item enters Floor." << endl;
}
virtual void Enter(Flagstone *fs)
{
cout << "Item enters Flagstone." << endl;
}
};
class Box : public Item
{
public:
static int count;
virtual void Enter(Floor *fl)
{
cout << "Box enters Floor." << endl;
}
virtual void Enter(Flagstone *fs)
{
cout << "Box enters Flagstone. Count++" << endl;
count++;
}
};
class Cherry : public Item
{
};
class Item;
class Floor
{
public:
/* Virtual Floor method. If object is in derived class,
it will call proper method. */
virtual void Enter(Item *it);
};
class Flagstone : public Floor
{
public:
virtual void Enter(Item *it);
};
class Wall : public Floor
{
};
/* Virtual Floor method. If object is in derived class, it will call proper method. */
void Floor::Enter(Item *it)
{
/* OK, we have Floor and Item or Item sub-class now we call item method, enter */
it->Enter(this);
}
void Flagstone::Enter(Item *it)
{
/* OK, we have Flagstone */
it->Enter(this);
}
int Box::count = 0;
void Enter(Floor *fl, Item *it)
{
fl->Enter(it);
}
int main(void)
{
Floor *fl = new Flagstone;
Item *it = new Box;
Enter(fl, it);
return 0;
}
Related
This question already has answers here:
C++ virtual method not called as desired
(4 answers)
Closed 5 years ago.
I have an interface from which a user derives multiple classes which I have no knowledge of but still I want to call these derived classes common method Run().
The Event class is intended to be an interface so I know how to call my unknown UserEvents derived class, since they all must have that Run() method implemented.
I currently have some code and get an error that CallEvent can't allocate an abstract Event. I understand the error, but don't know how I can go about and execute this correctly.
Here's some minimal code example (WandBox):
#include <iostream>
class Event
{
public:
virtual void Run(int Param) = 0;
};
// This is a user event and I have no idea what the class name is,
// but I still have to call it's method Run() that is common to the interface "Event"
class UserEvent : public Event
{
public:
virtual void Run(int Param) { std::cout << "Derived Event Dispatched " << Param << std::endl;};
};
// This parameter is of pure abstract base class Event because
// I have no idea what my user class is called.
void CallEvent(Event WhatEvent)
{
WhatEvent.Run(123);
};
int main()
{
std::cout << "Hello World!" << std::endl;
UserEvent mE;
CallEvent(mE);
}
I took your sample code (Like so) and tried to make it running (for illustration):
#include <iostream>
class Event {
public:
virtual void Run(int Param) = 0;
};
// This is a user event and I have no idea what the class name is,
// but I still have to call it's method Run() that is common to the interface "Event"
class UserEvent: public Event {
public:
virtual void Run(int Param)
{
std::cout << "Derived Event Dispatched " << Param << std::endl;
}
};
// This parameter is of pure abstract base class Event because
// I have no idea what my user class is called.
void CallEvent(Event *WhatEvent)
{
std::cout << "in CallEvent(Event *WhatEvent):" << std::endl;
// Huh? WhatEvent = new Event();
// wrong: WhatEvent.Run(123);
// Instead, use ->.
// For pointers, check for non-nullptr is very reasonable:
WhatEvent->Run(123);
// obsolete: delete WhatEvent;
}
// second approach using a reference (as recommended in comments):
void CallEvent(Event &WhatEvent)
{
std::cout << "in CallEvent(Event &WhatEvent):" << std::endl;
WhatEvent.Run(123); // for references - select operator . is fine
}
int main()
{
std::cout << "Hello World!" << std::endl;
/* nullptr does not make sense:
* UserEvent *mE = nullptr;
* Go back to original approach:
*/
UserEvent mE;
CallEvent(&mE); // calling the first (with Event*)
CallEvent(mE); // calling the second (with Event&)
return 0;
}
Now, it is compilable and runnable. Output:
Hello World!
in CallEvent(Event *WhatEvent):
Derived Event Dispatched 123
in CallEvent(Event &WhatEvent):
Derived Event Dispatched 123
(Life demo on ideone)
I annotated every modification in comments inside the sample code.
According to my book, if I want to make an array of objects that are not in the same class but in the same class hierarchy, I need to use pointers:
class text
{
public:
void write(string text);
void show();
private:
string texte;
};
void text::write(string text)
{
texte = text;
}
void text::show()
{
cout << texte;
}
class text_with_stars : public text
{
public:
void show();
};
void text_with_stars::show()
{
cout << "*";
text::show();
cout << "*";
}
int main()
{
text* array[2];
array[0] = new text;
array[0]->write("Hello");
text_with_stars* pointer = new text_with_stars;
pointer->write("Hi");
array[1] = pointer;
for (int i=0;i<2;i++)
{
array[i]->show();
}
return 0;
}
But when I do this, the output is "HelloHi" meaning that the second object used the show version that is from text and not from text_with_stars, but I made it exactly the same way that the book described. What Is the problem??
Here is what is written in the book:
Question* quiz[2];
quiz[0] = new Question;
quiz[0]->set_text("Who was the inventor of C++?");
quiz[0]->set_answer("Bjarne Stroustrup");
ChoiceQuestion* cq_pointer = new ChoiceQuestion;
cq_pointer->set_text("In which country was the inventor of C++ born?")
cq_pointer->add_choice("Australia",false);
...
quiz[1] = cq_pointer;
The chapter right next to the one I was reading is about virtual functions and it explains that the system will always use the member functions of Question instead of ChoiceQuestion, looks like I should read more before asking questions on internet!
void show()
needs to be virtual in the base class if you want to use methods from derived classes from base class pointers
The reason this is happening is because the function you are calling is non-virtual.
Let's say we have a class Parent and a class Child inheriting from the parent:
class Parent {
public:
void f() {
cout << "Parent::f()" << endl;
}
};
class Child : public Parent {
public:
void f() {
cout << "Child::f()" << endl;
}
};
Now, let's make a pointer to a Parent and store a Child in it (polymorphism):
Parent *ptr = new Child;
ptr->f();
At this point, the compiler sees ptr having type Parent* and determines that the function to be called is Parent::f().
In order to call Child::f() when dealing with polymorphism? The Parent::f() must be defined virtual. The compiler then generates code to check at run-time the value that is stored in memory to call the appropriate (child) function.
In short: ONLY when a function is virtual and is called on a pointer or reference, a memory lookup is made to determine the actual type at that point in memory. Otherwise it is not.
I got stuck with a C++ compilation error while doing something that is probably not really "conventional".
To make things easier I just re-wrote the mechanism I am trying to use in a easier-to-read way and I checked that I got the same issue.
First of all here is the code:
test.h // -- C++ --
template <typename MODULE> class item;
template <typename MODULE>
class init {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp;}
init() {}
virtual ~init() {}
private:
friend class item<MODULE>;
};
template <typename MODULE>
class item {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
item(init<MODULE> params) : m_fp(params.m_fp) {}
virtual ~item() {}
};
class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Method CB
int func1(int i);
// Item member
item<user> m_item;
public:
user();
virtual ~user();
};
test.cpp // -- C++ --
#include "test.h"
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {}
int user::func1(int i) {return 1;}
and here is the error:
/test.cpp:5:59: error: invalid use of non-static member function
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {
^
So, I am not sure this is the best way to achieve what I want (probably not, anyway if you have other suggestions they are very welcome) but my goal now is to make it work or to understand exactly why it can't work so that I learn something from it!
The basic idea is that:
the class "item" can be initialized with the named parameter idiom using the method "has_funcPtr" of the class "init" concatenated to its constructor like: "init().has_funcPtr(&function_name)".
the class "user" can store a pointer to its private method "func1" as a private member of its private member of type "item".
In this way, when a specific method of an object "item" is called (for simplicity I don't include this long part here since it is not relevant to the error but it is just to describe the goal of this snippet of code) that method can do stuff and call the private method of its father object "user" through that pointer to function (I hope this is clear enough...).
Now, I think there is an issue with the order of initialization of the objects but I am not sure where and how to fix it.
In particular I thought that since the "func1" method doesn't operate on any member of the class "user", then its reference could be used directly in the initialization list to initialize an "init" object and feed it to an "item" object.
Thank you all in advance
this->func1 doesn't form a member function pointer. It should look like &user::func1 if you are in the user class.
I post here the complete answer to my issue. I developed it after the suggestion from Bo and after understanding how to point to an instance specific method through a pointer to it.
In short, two things are really important to note:
A pointer to a non-static class member function could be thought at as just an offset rather than an "absolute address" (http://www.codeguru.com/cpp/cpp/article.php/c17401/C-Tutorial-PointertoMember-Function.htm). This means that you can't access that function (it is just an offset) without first having an instance pointer. Once you have the instance pointer, with this "offset pointer" you can call that method using:
(object_ptr->*method_ptr)(parameters_here)
A better way would be to use a #define macro since this syntax is really error prone and complex to read (https://isocpp.org/wiki/faq/pointers-to-members):
#define CALL_MEMBER_FN(ptrToObject,ptrToMember) ((ptrToObject)->*(ptrToMember))
and then use it as:
CALL_MEMBER_FN(object_ptr, method_ptr)(parameters_here)
Following the first point, if you want a nested class to be able to call the upper class method by a pointer to it, you also need to pass the upper class instance pointer to access that function. In my case, since I wanted to be able to decide case by case if that method should be called or not, I used the Named Parameter Idiom (below note that func2 is not registered for example).
Finally here is the revised code that it works (tested):
-- C++ -- test.h
#include <iostream>
template <typename MODULE> class item;
template <typename MODULE>
class init {
public:
typedef int (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr m_fp;
func2Ptr m_fp2;
MODULE* m_dad;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp; return *this;}
init& has_func2Ptr(func2Ptr fp2) { m_fp2 = fp2; return *this;}
init(MODULE* dad) : m_dad(dad) { std::cout << "init constructor called\n"; }
~init() {}
private:
friend class item<MODULE>;
};
template <typename MODULE>
class item {
public:
typedef int (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr m_fp;
func2Ptr m_fp2;
MODULE* m_dad;
public:
item(init<MODULE> params) :
m_fp(params.m_fp),
m_fp2(params.m_fp2),
m_dad(params.m_dad)
{
std::cout << "item constructor called\n";
}
~item() {}
// Method invoked externally
int callback() {
std::cout << "item class method callback invoked\n";
// In the real case here do general stuff
if(m_fp) {
int i = (m_dad->*m_fp)(1); // call member function through its pointer
return i;
} else {
std::cout << "callback not registered\n";
return 0;
}
}
// Method invoked externally
bool callback2() {
std::cout << "items class method callback2 invoked\n";
// In the real case here do general stuff
if(m_fp2) {
bool b = (m_dad->*m_fp2)(true); // call member function through its pointer
return b;
} else {
std::cout << "callback2 not registered\n";
return false;
}
}
};
class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Methods that optionally add more functionalities to the 2 callbacks
int func1(int i);
bool func2(bool b);
public:
// Item member
item<user> m_item;
public:
user();
~user();
};
-- C++ -- test.cpp
#include "test.h"
user::user() : m_item(init<user>(this).has_funcPtr(&user::func1) ) {
std::cout << "user constructor called\n";
}
int user::func1(int i) {return i;}
bool user::func2(bool b) {return b;} // func2 won't be registered
int main() {
user* u = new user();
// Test callbacks
int i = u->m_item.callback();
bool b = u->m_item.callback2();
std::cout << "main is printing i=" << i << " and b=" << b << "\n";
std::cout << "expected results are i=1 and b=0\n" << "END\n";
return 0;
}
OUTPUT:
init constructor called
item constructor called
user constructor called
item class method callback invoked
items class method callback2 invoked
callback2 not registered
main is printing i=1 and b=0
expected results are i=1 and b=0
END
I have a large class with many methods. This class has a subclass that manages a different situation.
Just to clear it up with an example the actual situation is the following:
class Logic {
public:
virtual void method()
{
Something::getInstance()->doSomething();
}
};
class ArrayLogic : public Logic {
private:
Something** array;
public:
void method() override
{
for (int i = 0; i < AMOUNT; ++i)
array[i]->doSomething();
}
};
Now this pattern repeats itself in multiple methods and I'd like to have just one implementation without trading for performance (since some of this methods are actually already proven to require efficiency).
I was thinking if it's possible with C++11 to have a template solution approach which is able to manage this situation at compile time without the necessity to duplicate the code.
Mind that the array doesn't make sense to exist for Logic so having a Something*[1] is not a viable option.
An additional problem is that at the moment Something** array is not directly contained in ArrayLogic but resides in another class, so it's more like
class ArrayLogic : public Logic {
private:
Container* container;
public:
void method() override {
for (int i = 0; i < AMOUNT; ++i)
if (container->array[i])
container->array[i]->doSomething();
}
}
While having to check for container->array[i] != nullptr may seems strange the fact is that the position is relevant, so an element removed from the array doesn't cause a shift of the successive element but leaves a hole.
I'd try and create separate classes for single and multiplayer games. Base both of these on a base class LogicBase that has a method(Something*) function that calls doSomething() on its parameter. This is what #Pradhan was referring to.
In your main game, you can use a LogicBase* to refer to either a SinglePlayerLogic or a MultiPlayerLogic object and call the relevant method() using a virtual function call.
I'm passing what is stored in Container to the constructor of MultiPlayerLogic. But it could be in a separate class and accessed that way. Similarly, it may be cleaner to pass a Something to the constructor of SinglePlayerLogic, but I wanted to keep the code structure close to your original, so didn't do this.
It initially looks funny for LogicBase to call to a subclass, then have those subclasses call the protected method(Something*) back in the super class. I've seen it elsewhere as a design pattern, but can't recall it's name.
#include <iostream>
#include <vector>
const int AMOUNT = 5;
struct Something {
void doSomething() { std::cout << "Something::doSomething\n"; }
static Something* getInstance() { static Something s; return &s; }
};
class LogicBase {
public:
virtual void method() = 0;
protected:
void method(Something* s) { s->doSomething(); }
};
class SinglePlayerLogic : public LogicBase {
public:
void method() override
{
std::cout << "SinglePlayer::method\n";
LogicBase::method(Something::getInstance());
}
};
class MultiPlayerLogic : public LogicBase {
public:
MultiPlayerLogic(Something **s) : players(s) {}
void method() override
{
std::cout << "MultiPlayer::method\n";
for (int i = 0; i < AMOUNT; ++i) {
if (players[i] == nullptr) {
continue;
}
std::cout << i << " ";
LogicBase::method(players[i]);
}
}
private:
Something** players;
};
int main() {
LogicBase* lb;
SinglePlayerLogic spl;
lb = &spl;
lb->method();
std::vector<Something*> players{AMOUNT};
MultiPlayerLogic mpl(players.data());
lb = &mpl;
lb->method();
}
The Non-virtual Interface idiome (NVI) is pretty self explanatory: You don't write public virtual functions, but public functions that call a private virtual implementation function, like so:
class Object{
virtual void v_load();
public:
void load(){ v_load(); }
}
This enables you, the base class author, to check and enforce pre- and post-conditions or apply other functions so the author of deriving classes can't forget about them.
Now when you are the deriving author, you may want to write a base class yourself - let's call it Pawn - that extends on the functionality of load() and therefore has to override v_load(). But now you are facing a problem:
When you override v_load(), other clients that want to derive from your class, will always overwrite that behaviour, and they can not call Pawn::v_load() because it is a private function, neither can they call Pawn::load() because it is defined as { v_load; } in Object which will of course lead to an infinite loop. Additionally, requiring them to do so could lead to mistakes when they forget that call. If I would want them to enable that, I would have to specify the acces to v_load() as protected in Object, which seems like an ugly solution as it would weaken the encapsulation of Object greatly.
You could of course still override v_load() to call a new function v_pawnLoad(), which is then overridden by clients, but that seems very error-prone as a lot of clients will probably overload the wrong function.
So, how can I design Pawn in such a way that clients can still override v_load() while keeping the ability to check pre-conditions or call other functions and (if possible) not enabling, let alone requiring clients of Object or Pawn to call the base v_load() implementation?
If your intention is to allow people to "extend" as opposed to "replace" load's behaviour, then put the code you currently have in v_load in load then call an empty v_load in the end.
Or you could just make v_load protected if you want to let people choose between "replacing" or "extending".
If you just want to allow them to replace the behaviour, your code is fine as it is.
As a bonus, in all these 3 variants you can change "allow" with "force" by making your v_load a pure virtual if you have no default behaviour.
If you wish to limit the override to your Pawn child class, add the final keyword to v_load in Pawn and use another virtual function to allow children of Pawn to customise its behaviour.
How about mixin' in some CRTP?
#include <iostream>
class BaseObject
{
private:
virtual void v_load() = 0;
public:
void load() { v_load(); }
};
template<typename Derived>
class Object : public BaseObject
{
private:
virtual void v_load() { static_cast<Derived&>(*this).load(); }
};
class Pawn : public Object<Pawn>
{
public:
void load() { std::cout << "Pawn::load()" << std::endl; }
};
class BlackPawn : public Pawn
{
private:
virtual void v_load() {
std::cout << "BlackPawn::v_load()" << std::endl;
std::cout << "- "; Pawn::load();
}
public:
void load() {
std::cout << "BlackPawn::load()" << std::endl;
std::cout << "- "; Pawn::load();
}
};
class BigBlackPawn : public BlackPawn
{
private:
virtual void v_load() {
std::cout << "BigBlackPawn::v_load()" << std::endl;
std::cout << "- "; BlackPawn::load();
}
public:
void load() {
std::cout << "BigBlackPawn::load()" << std::endl;
std::cout << "- "; BlackPawn::load();
}
};
template<typename T>
void load(T& x)
{
x.load();
}
void vload(BaseObject& x)
{
x.load();
}
int main()
{
Pawn p;
BlackPawn bp;
BigBlackPawn bbp;
load(p);
load(bp);
load(bbp);
std::cout << std::endl;
vload(p);
vload(bp);
vload(bbp);
}
Output on ideone.