Click here to Skip to main content
15,888,984 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

See the code:
C++
class BaseData {
  public:
  BaseData() {}
  virtual int add() = 0;
  virtual int multiply() = 0;
  virtual int click() = 0;
  virtual int clack() = 0;
};

class Derived : public BaseData {
  int a, b;
  public:
  Derived(int a, int b) : BaseData() {
    this->a = a;
    this->b = b;
  }
  int add() {
    return a + b;
  }
  int multiply() {
    return a * b;
  }
  int click() {return 0;}
  int clack() {return 0;}
};

class Other : public BaseData {
  int a, b;
  public:
  Other(int a, int b) : BaseData() {
  	this->a = a;
    this->b = b;
  }
  int click() {
    return a + b;
  }
  int clack() {
    return a * b;
  }
  int add() {return 0;}
  int multiply() {return 0;}
};

class Operator {
  int (BaseData::* operation)();
  BaseData *obj;
  public:
  Operator(BaseData *object, int (BaseData::*op)()) : obj(object) {
    this->operation = op; 
  }
  int doOperation() {
    return (obj->*operation)();
  }
};


Derived *data1 = new Derived(33, 3);
Other *data2 = new Other(50, 2);
Operator *o1 = new Operator(data1, &BaseData::add);
Operator *o2 = new Operator(data1, &BaseData::multiply);
Operator *o3 = new Operator(data2, &BaseData::click);
Operator *o4 = new Operator(data2, &BaseData::clack);

void setup()
{
  Serial.begin(9600);
}

int main()
{
  Serial.write(o1->doOperation());
  Serial.write(o2->doOperation());
  Serial.write(o3->doOperation());
  Serial.write(o4->doOperation());
}


I'd like to avoid that the referenced methods have to be declared in the Base class, and defined in all derived classes.

What I have tried:

I Tried to define a typedef into a Base class, but without success:
C++
class BaseData {
  public:
  typedef int (BaseData::*fx)();
  BaseData() {}
};

class Derived : public BaseData {
  int a, b;
  int _add() {
    return a + b;
  }
  int _multiply() {
    return a * b;
  }
  public:
  Derived(int a, int b) : BaseData() {
  	this->a = a;
    this->b = b;
  }
  fx add = &Derived::_add;
  fx multiply = &Derived::_multiply;
}


The compiler return this error
error: cannot convert 'int (Derived::*)()' to 'BaseData::fx {aka int (BaseData::*)()}' in initialization


There is another way? Where am I wrong?
Posted
Updated 18-Dec-19 21:15pm
v2
Comments
[no name] 16-Dec-19 14:03pm    
Who forces you to define the methods in the base class as pure abstract?
Menci Lucio 17-Dec-19 3:49am    
The point is not this one. The point is that I'd like to not define them in the base class... I think that if I don't find an elegant solution I will define all methods in the base class as not abstract ones.
Stefan_Lang 17-Dec-19 9:24am    
Your request isn't clear: if you don't want to define the functions in your base class, then why do you even have a base class?

To clarify what you actually want, please provide an example on how you intend to call one of these functions.

P.S.: sorry: I've just noticed that your first code block has a scroll bar - i missed the code further down

This is C++ so you don't have to mess with function pointers. You can use virtual methods and just override the ones you want customized. If you are using the functions as windows callbacks or thread procedures they must be static members because there are no "this" pointers used with those.

I see no compelling reason to use function pointers in the code you have shown so I would avoid them.

It just so happens I wrote a little program that used function pointers a while ago. Here is a brief code excerpt I used in it:
C++
typedef BaseObject* ( * ObjCreateFunc )();

typedef struct
{
    UINT          controlId;
    ObjCreateFunc createFunc;
} IdMap;

IdMap Map[ MAX_OBJECTS ] = { 0 };

// it was invoked like this:

BaseObject * pobj = (* Map[ index ].createFunc )();
I recently rewrote this section using a Factory pattern and it is a LOT cleaner now. It no longer uses function pointers to create the objects. It uses a virtual object factory class that is overriden to create each of the individual objects. There are eighteen different objects that can be created, depending on which button is pressed and there is a similar array of structures that associates a control identifier with an object factory.
 
Share this answer
 
Maybe function pointers is what you are looking for. Read this Typedef for Function Pointers.

But I warn you: this is hard core C and you may get some headaches till you are mastering it. ;-)
 
Share this answer
 
Comments
Menci Lucio 16-Dec-19 12:33pm    
This is what I had trying to do, but I was not able to use the function pointer defined in the base class to define a function in the derived class:
the line
fx add = &Derived::_add;
returned the error
error: cannot convert 'int (Derived::*)()' to 'BaseData::fx {aka int (BaseData::*)()}' in initialization

This was the result of my headache :-)
Menci Lucio 17-Dec-19 3:44am    
Hi, thank you, but if I don't want to use virtual methods and override them there are some reasons. I have a lot of subclasses of the BaseClass in my production project, for example, there are led lights (the virtual methods has to be switchOn, switchOff, switchState, startTimer, blink, blinkFast), serialQueue (sendLocalMessage, sendGlobal, sendARequest), display (showState, switchOff, showError), and many others. I tried to define all virtual methods in the base class, but all of them has to be defined into derived ones (see the code I posted).

The last but not least reason is I'd like to know if there is a way to do that, for personal knowledge, and for pride :-)
Stefan_Lang 17-Dec-19 9:51am    
This sounds very much as if your class hierarchy is broken. It doesn't make any sense to create a class that is a base to literally everything else. It's a big difference if your actual class is a LED light or a washing machine: both might be turned on or off, but the similarities stop at dimming or blinking. You don't want or need a class that can be both.

If you absolutely must have a global baseclass for EVERYTHING for some obscure reason, you really have to introduce intermediate layers in your class hierarchy: define an intermediate class for lights, another for toasters, and another for washing machines. And then use these intermediate base classes in your program, not the ultimate (and IMHO entirely pointless) baseclass.
Rick York 17-Dec-19 11:19am    
I agree with Stefan. One more thing - I think it's OK to have the base class but you don't have to make everything purely virtual (=0). You can provide defaults that are just empty brackets at least "{}". This means you only need to implement what is necessary. I also agree with him about intermediate layers such as for Lights. It can still derive from the base class but it would have real implementations of the on and off methods. You could even make a further specialization for lights that can be dimmed (LightDim), assuming that not all of them can be which is true for some kinds.
Sorry for the late answer, but I couldn't quite decide how to take your example code, as the functionality presented there makes no sense, and I couldn't come up with a good alternative example that would make more sense without changing the implied requirements too much.

Anyway, I'll tell you what I think of this:

1. In C++ there is absolutely no need for function pointers of any kind. I've been programming in C++ since before the advent of one-stage compilers some time in the mid-80s, and I've never come across requirements that couldn't be solved with a reasonable set of classes and polymorphism. Whatever it is you actually wish to achieve, you can make it work with a reasonable hierarchy of classes.

While I've seen corner cases where such a solution wasn't practical due to unusal restrictions, there is nothing like that that I can see in your question.

Which leads us to:
2. You didn't give us a meaningful specification. The example code doesn't seem to fulfil any meaningful function, and even without knowing how you implemented the solution, the code that uses it seems to be weird: all it does is throwing independent data into the same pot, and then trying to fit square objects into a round hole, if you get my meaning. Either you have to give us example code that reflects how you actually mean to use the solution, or, better, give us the original specification if you have one.

3. I can make some educated guesses about what you need, but not code that turns your weird example into something that makes any sense. let's start with some observations:

a) your classes appear to try implementing something that is known as the Command Design Pattern. See Command pattern - Wikipedia[^]

b) in your classes, you've defined a restricted set of functions, as well as the arguments that these functions are supposed to operate on. It's not a good idea to specify more than one function per class though: if for some reason you need to somehow change the argument number or types for only one of these functions, how can you resolve that? You've created one-to-one relationships between the functions and the data. If you have multiple functions operating on the same data, then either you need to duplicate the data and put each function and associated data into a separate object, or you need to put the data into a separate object, apart from the functions.

c) you have multiple levels of abstractions, and on the last level, you only call one function: doOperate(). Why not define your classes in such a manner that they implement exactly one function each?

4. The above leads me to believe you really need to implement the Command Pattern. I could offer code to fit your example, but the site I linked above already does a good job explaining what you need, and it does offer some example code too (the C++ example is at the bottom of the page). Try it.
 
Share this answer
 
Comments
Menci Lucio 19-Dec-19 4:46am    
Yes, of course, you are in right. After a lot of headaches caused by my wrong choice, I build my project from 0 using some command classes.
I'm a newbie about c++, I'm writing in C# and I was wondering if there is a way to make something like events. But C++ is not c#. Maybe C# events was made by command pattern...

Thank you

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900