tags:

views:

214

answers:

5

I just cannot imaginate a way to do a call to a function with genericity. I have a code which a have to call a function in two different classes in different moments.

I have A and B classes which I can access one time or other time. Or I access A or I access B. Not both in the same type.

I have code this program but I just cannot imagine how to do this. Or if this is good for performance or codding. I just want to eliminate the C class but I don't know how.

Any idea?

class MyClass  
 {  
    public:  
       MyClass() {} //contructor padrão, não deve ser utilizado isoladamente  

     virtual int a() = 0;  
     virtual int b() = 0;  

     int c()
     {
      return b();
     }

 };  

class A : public MyClass  
{  
    public:  
     int a() { return 1; }  
     int b() { return 1; }  
     int d() { return 1; }  
};  

class B : public MyClass  
{  
    public:  
     int a() { return 1; }  
     int b() { return 1; }  
     int e() { return 1; }  
};  

class C 
{  
public:  
    A ca;  
    B cb;  

    enum TIPO { A, B };  
    TIPO Tipo;  

    C(TIPO tipo) { Tipo = tipo; }  

    int a()  
    {  
     switch(Tipo)  
     {  
     case A:  
      return ca.a();  
      break;  
     case B:  
      return  cb.b();  
      break;  
     default:  
      break;  
     }  
    }  

};  


void main()  
{  
    C c(C::B);  
    c.a();   
    return;  
}  
+2  A: 

If I understand you correctly, you are trying to eliminate the members (ca,cb), and just call the appropriate base class method.

If that's the case, it can be done by using:

switch(Tipo) {
case A:
    return A::a();
case B:
    return B::a();
}

However, I would recommend revisiting your design. Typically, situations like this can often be handled by rethinking/reworking the class design so that there is a single base class or interface which defines a(), and instead of creating one concrete class with 2 base classes, create one of two specific, concrete classes derived from a single base class. There is no need for multiple inheritance here. (This is especially true since you know the type at construction time.)

Reed Copsey
Two colons! A::a() and B::a()
jmucchiello
Thanks - simple typo - fixed.
Reed Copsey
A: 

First of all, decide if your A and B classes will belong to C by inheritance or by composition. Right now you're doing both, which is both bloating your code and making it confusing.

If you do go for inheritance, then you have another problem: similarly named overridden methods, a prime cause for the Deadly Diamond of Death. Multiple inheritance, in case you haven't heard, is evil. Avoid it unless there is no other way to get the job done.

If you go with composition (my recommendation), then it seems to me that your specification of "not at the same time" becomes unnecessary. You're not accessing the same data, so there's no possibility of a race condition. And if you are (for some ungodly reason) determined to access the same memory space, then you'll need to brush up on multithreading, the implementation of which will differ with each platform you develop on.

rtperson
Its not called the diamond of death!! Its the Diamond problem. It's not going to kill you or even cause your program to crash or exit unexpectadily. It will just give you unexpected results unless you know about it. It does not make mulitple ineritance evil, it just makes it more powerful (more power requires more care for the beginner). To be honest its not that big of a deal.
Martin York
I've also heard it referred to as the "Fragile Base Class" problem. But in this case it is a problem, since both inherited classes share the same parent, and override methods a() and b(). An experienced programmer would avoid both these errors.
rtperson
I am an experienced programmer, I don't see a problem. What is it. If you try and use a() or b() the compiler will tell you there is a ambiguity. You must solve the ambiguity before continuing. No problem. An experienced programmer would not necassirily avoid multiple inheritance solely over this issue (Not that I advocate it either) but you need to pick your words carefully here.....
Martin York
Well, the OP has kind of mooted the point here: the C class no longer inherits from A and B. I see your point, but outside of Stepanov and Lee's original STL implementation, I've rarely seen multiple inheritance solve a problem that could not be solved in a cleaner way, either through delegation or abstract interfaces. And if I were to use multiple inheritance, I'd use it to mix in distinct function sets, and not to incestuously mingle together classes that are already closely related, as the OP did. That's what leads me to call the original code an error rather than a shrug-worthy ambiguity.
rtperson
A: 

Ok, I guess you want C::a() to call A::a() or B::b() depending on what "type" or "mode" C has. First of all there is no need to let C inherit A and B.

class C
{
  private:
    A ca;  
    B cb; 

    enum TIPO { A, B };  
    TIPO Tipo;

  public:
    SetTipo(TIPO tipo) { Tipo = tipo; }

    // ..
};

void main()  
{  
    C c(C::B);  // Start with mode B and call B::b()
    c.a();
    c.SetTipo(C::A); // Now I'm in mode A .. call A::a()
    c.a();   
    return;  
}

This assumes that C really should own one instance of A and one instance of B and I'm not sure if that's what you want. Your question didn't state if that's the case or not.

Cheers

Magnus Skog
A: 

As you've written 'A' and 'B', you don't actually need the C class. By declaring your member functions "virtual" you are using run time polymorphism and this will result in the "correct" functions being called:

void foo (MyClass & mc) {
  mc.a ();
}

int main () {
  A a;
  B b;

  foo (a);  // 'mc.a()' will call 'A::a'
  foo (b);  // 'mc.a()' will call 'B::a'
}

Is there some other reason that you need to inherit from C?

Richard Corden
A: 

This question is very unclear. I have another interpretation of the question, along with an answer.

Interpretation: given:

 class C {
 public:
  int a();
  int b();
 };

You want to call either method a() or method b(), selectable at runtime. Solution: member function pointers.

A member function pointer is like a regular C function pointer, except that it applies to a method in a class, and its type signature includes the name of the class it's invoked on. Here's how to use one with the class I've just given:

  typedef int (C::*SELECT_FUNC)(void);

This is the declaration of the member function pointer. It is similar to the declaration of a regular C function pointer, with the addition of a class name. Now we can assign it:

 SELECT_FUNC ptr = &C::a;
 SELECT_FUNC other_ptr = &C::b;

And to call:

 C item;
 C *item_ptr;

 int rv = item.*ptr();
 int rv2 = item_ptr->*other_ptr;

This syntax is funky. Think of the "*" as "dereference". We are dereferencing the member function pointer to get a METHOD, at which point we can invoke the method in what is otherwise the normal way.

The cool thing about this is: it doesn't even matter if the methods are virtual or not. You can assign either a virtual method or a non-virtual method to a member function pointer. If you call a method through a function pointer and the method happens to be virtual, then you'll get a true virtual call (i.e. if the function pointer is declared to point to a base class method, but you use a derived class instance for "this", then the derived class method will be called, just as it is for a normal virtual call.)

I would think through your requirements carefully. Your question is not well asked, which leads me to believe that you do not understand yourself what you really want to achieve. Once you understand what you want to achieve, then either a class hierarchy or member function pointers (or both) may be the best choice to solve your problem.

d3jones