0

Given the following piece of code as a minimum working example:

#include <iostream>

class Object_A
{
public:
    int attribute_a,attribute_b;
    
    Object_A(int a,int b){
        this->attribute_a = a;
        this->attribute_b = b; 
    }
    
    int object_method(){
        std::cout << "Hello from Object A: " << std::endl;
        return (this->a + this->b);
    }
    
};

class Object_B
{
public:
    int attribute_c, attribute_d;
    
    Object_B(int c,int d){
        this->attribute_c = c;
        this->attribute_d = d; 
    }
        
    int object_method(){
        std::cout << "Hello from Object B" << std::endl;
        return (this->c + this->d);
    }

};


class Object_Omega
{
public:
        
    Object_A alpha;
    Object_B beta;
    
    Object_Omega (Object_A first, Object_B second):
        alpha(first),
        beta(second)
    {}

    int foobar(int a){ return a; }
    
};

void according_to_user_input(bool input,Object_Omega obj)
{
    
    void * either_A_or_B;
    
    if (input){ either_A_or_B = & obj.alpha; }
    else      { either_A_or_B = & obj.beta;  }
    
                       /* problem here */
    for(int i = 0; i < either_A_or_B->object_method(); i++)
    {
        std::cout << i << std::endl;
    }

}

int main()
{   
    /* this happens somewhere */
    Object_A new_A = Object_A(1,2);
    Object_B new_B = Object_B(3,4);
    Object_Omega W = Object_Omega(new_A, new_B);

        
    according_to_user_input(true/*false*/, W);
    
    return 0;
}

I wish to use a void pointer (e.g., inside the function according_to_user_input) but I am struggling to comprehend the proper way to do this. Similar questions have been asked [1], [2] but I did not manage to make this work in the case of the values being pointed towards from the pointer being custom objects.

Given the user input I wish to invoke the object_method() either from A or from B through the Omega object. Unfortunately the code that I've been working on has this showcased behavior as is and not as an inheritance relationship between the objects in order to avoid the ugly void C-like and definitely not C++ -like scenario.

Thank you in advance!

underscore_d
  • 6,309
  • 3
  • 38
  • 64
ex1led
  • 427
  • 5
  • 21
  • I am not sure how representative your example is and if you are allowed to use C++11 but generally I would use inheritance from one common base class, smart pointers (e.g. `std::shared_ptr`) and `virtual` functions to avoid this altogether. If necessary you can use `std::static_pointer_cast`. – 2b-t Apr 26 '21 at 11:42
  • Similar to the answer I have given yesterday [here](https://stackoverflow.com/a/67252185/9938686). – 2b-t Apr 26 '21 at 11:44

2 Answers2

4

You cannot indirect through a pointer to void. And there is no need for a pointer to void.

The simplest solution is this:

int number = 1;
std::cout << input
    ? obj.alpha.object_method(number)
    : obj.beta.object_method(number);

For the edited question: The above still works, but you can get rid of the repetition of the complex code using a function template. Here is an example using a lambda:

auto do_stuff = [](auto& either_A_or_B) {
    for(int i = 0; i < either_A_or_B.object_method(); i++)
    {
        std::cout << i << std::endl;
    }
};
input
    ? do_stuff(obj.alpha)
    : do_stuff(obj.beta);

P.S. Avoid using C-style casts.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I would advise the OP to rewrite the code if possible to use polymorphism instead. – 2b-t Apr 26 '21 at 11:48
  • 2
    @2b-t Based on the question, OP seems to be aware of that already. The said `Unfortunately the code that I've been working on has this showcased behavior as is and not as an inheritance relationship`. – eerorika Apr 26 '21 at 11:50
  • Hello @eeronika. Thanks for your reply. Maybe I did not explain it correctly. I will edit the post so there is a better explanation of what I wish to do. It is true, that given this example I gave the problem can be solved by a simple if-then case on the user input. – ex1led Apr 26 '21 at 11:59
  • @eerorika I updated the example. Hopefully it makes more sense now. – ex1led Apr 26 '21 at 12:05
  • Much obliged! So Templates and(/or) lambdas would be the way to 'think' when it comes to such issues in C++ ? Meaning avoid composing duplicate code segments and generalizing the functions to make them applicable to >1 types. – ex1led Apr 26 '21 at 12:16
  • 1
    @ex1led Templates are a way of generating classes and functions that are otherwise identical except for types or compile time values that are provided as arguments for the template. So, if you want to do X for an object of type A and you want to do the same X for an object of an unrelated type B, then template is a convenient way to generate both X(A) and X(B) without repetition. This is sometimes called "generic programming". – eerorika Apr 26 '21 at 12:18
2

This is not a good use for void* and if, like you comment, you can't make use of inheritance and the actual problem is more than just console output, then you could still make it generic with a function template

template <class T>
void according_to_user_input(T &obj)
{
    std::cout << obj.object_method();
}

and use it like so

if (input)
    according_to_user_input<Object_A>(W.alpha);
else
    according_to_user_input<Object_B>(W.beta);
acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • Oh, templates. This may be what I need! I have not considered that. I am not that experienced with the language but I do think that this may be also a solution to my problem based on what I've read. I will look into it. Thank you. – ex1led Apr 26 '21 at 12:07