0

I have a problem with the following situation:

 template<class T>
class A {
public: virtual int  f() { return 1; }
};

class BaseA : public A<BaseA> {};
class DerivedA : public BaseA, public A<DerivedA> {};

and when I do:

 BaseA* b1 = new DerivedA;
b1->f();

it calls A<BaseA>::f() instead of A<DerivedA>::f() and I don't know how to fix it.

Josh
  • 23
  • 5
  • Better post some real code that compiles. See http://stackoverflow.com/help/mcve. – juanchopanza Jun 19 '15 at 09:55
  • You have an inheritance diamond here. Use virtual inheritance to solve the issue. – utnapistim Jun 19 '15 at 09:55
  • 1
    `A` and `A` are entirely different, unrelated types. – Kerrek SB Jun 19 '15 at 09:58
  • 2
    @utnapistim I don't see a diamond here. `A` and `A` are different types. – TartanLlama Jun 19 '15 at 09:58
  • @utnapistim: I question that. – Kerrek SB Jun 19 '15 at 09:58
  • Is your code compiling? This doesn't look compilable – Spanky Jun 19 '15 at 09:59
  • template ... virtual?! read [this](http://stackoverflow.com/questions/2354210/can-a-member-function-template-be-virtual) first. – user1810087 Jun 19 '15 at 10:00
  • I changed the code in the post, now it compiles, Sorry. – Josh Jun 19 '15 at 10:01
  • @user1810087 This is a class template with a virtual member function, not a virtual member function template. – TartanLlama Jun 19 '15 at 10:02
  • @user1810087 so there is no way to fix it? – Josh Jun 19 '15 at 10:04
  • 1
    You cannot override virtual functions by inheriting from an additional base class. To override a function, you must define it in the class itself. – Kerrek SB Jun 19 '15 at 10:09
  • I think you could separate your `Base` behaviour into another class (something like `BaseBehaviour`), then have `struct Base : BaseBehaviour, A` and `struct Derived : BaseBehaviour, A`. Hard to tell without more information though. – TartanLlama Jun 19 '15 at 10:15
  • @KerrekSB: To be more precise, one cannot override a virtual function by inheriting from an additional base class *in the way shown here*. More generally it's possible by using dominance in a virtual inheritance hierarchy. Well except that for diagnostic free build it's then necessary to turn off a silly-warning in Visual C++. :( – Cheers and hth. - Alf Jun 19 '15 at 10:19
  • @Cheersandhth.-Alf: No, I mean this quite generally. Consider `struct X { virtual void f() = 0; };`. There is no way to define a derived, concrete class that does not define `f` (possibly in some intermediate base), in particular, no amount of additional inheritance can implement `f` for you. – Kerrek SB Jun 19 '15 at 11:03
  • @KerrekSB: http://coliru.stacked-crooked.com/a/b02aeae93604e5a9 – Cheers and hth. - Alf Jun 19 '15 at 11:13
  • @Cheersandhth.-Alf: Ah, nice trick. Yes, that works. So I'll have to revise my statement to say "a non-virtually derived, concrete class". Virtual inheritance means that the virtual base class is considered only a base of the most derived class, which is what I wanted to cover by "intermediate base": Your `Derived` is concrete because it inherits from the concrete `Impl`. – Kerrek SB Jun 19 '15 at 11:15

2 Answers2

1

Additional info from the OP: this is a homework problem where class A can be freely changed, but classes BaseA and DerivedA cannot be changed.

Then the following is one solution, based on dominance in a virtual inheritance hierarhcy:

#include <iostream>
#include <typeinfo>
using namespace std;

struct BaseA;

struct I
{
    virtual auto  f()
        -> int = 0;
};

template<class T>
class A
    : public virtual I
{
public:
    virtual auto  f()
        -> int override
    { cout << typeid( T ).name() << '\n'; return 1; }
};

template<>
class A<BaseA>: public virtual I {};

class BaseA : public A<BaseA> {};
class DerivedA : public BaseA, public A<DerivedA> {};

auto main() -> int
{
    BaseA* b1 = new DerivedA;
    b1->f();
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 1
    Sorry, I need to get myself some coffee, I'm just out of bed. Anyway the above *works*. Proving that I can solve things without understanding them. :) – Cheers and hth. - Alf Jun 19 '15 at 10:22
  • I can't change class BaseA or class DerivedA(Homeworks :) ). I can add more classes,structs or add functions/specialization to A, so is there any other way to make b1 call A instead of overriding f() ? – Josh Jun 19 '15 at 10:45
  • @Josh: OK, I got some coffee now. Class `BaseA` is entirely defined by class `A`, and you invoke via a pointer to `BaseA`, where the most derived class doesn't override anything. Thus if something isn't in `A` it doesn't influence the result. And `A` certainly isn't there: it's an unrelated class. – Cheers and hth. - Alf Jun 19 '15 at 10:54
  • @Josh: After consuming some more coffee, and posting a dominance example to KerrekSB, I realized **I was wrong again** (about impossibility). So, replaced answer wholesale. – Cheers and hth. - Alf Jun 19 '15 at 11:22
0

The Following program calls f from derivedA (output : f in derived). Works fine.. anything wrong here ?

#include <iostream>
using namespace std;

template<class T>
class A
{
  public:
   virtual int f()
   {
       return 1;
   }
};

class BaseA : public A<BaseA>
{
  public:
  virtual int f()
  {
   cout << "f in base" << endl;
   return 1;
  }
};

class DerivedA :  public BaseA, public A<DerivedA>
{
   public:
   int f()
   {
       cout << "f in derived" << endl;
       return 1;
    }
};

main() {
    BaseA* b1 = new DerivedA;
    b1->f();
}
  • nothing wrong, but as I said in the comment below, I can't change BaseA or DerivedA. I need a way around this. – Josh Jun 19 '15 at 10:51