views:

98

answers:

3

I am extending an existing C++ project. I have a base class that derives from two parent classes. One of the parents has a pure virtual function. I want that pure virtual function to be defined by a function implemented in the other parent.

So, I want another parent to satisfy the base class's obligation to define a parent's pure virtual function. I have tried two approaches, both have lead to compiler errors.
Any ideas?

Here is a C++ program demonstrating my first idea, hoping the compiler would just use base2's definition of vfunc().

// This is my first approach, hoping the parent base2 of derived would satisfy the need to define
// base1's pure virtual vfunc.

class base1 {
public:
 virtual int vfunc() = 0;
};

class base2 {
public:
 int vfunc() { return 0;} //defined
};

class derived : public base1, public base2 {
public:
 //empty
};

int main()
{
 derived d;
 base1 & b1 = d;
 int result = b1.vfunc();
 return result;
}

The compiler reports that derived is still an abstract class:

$ gcc a.cc 
a.cc: In function ‘int main()’:
a.cc:26: error: cannot declare variable ‘d’ to be of abstract type ‘derived’
a.cc:18: note:   because the following virtual functions are pure within ‘derived’:
a.cc:7: note:  virtual int base1::vfunc()

Here is my second attempt:

// This is my second attempt, defining a vfunc in the derived class that calls the other parent.

class base1 {
public:
 virtual int vfunc() = 0;
};

class base2 {
public:
 int vfunc() { return 0; } // defined
};

class derived : public base1, public base2 {
public:
 int vfunc() { return base2::vfunc(); } // call the other parent's vfunc
};

int main()
{
 derived d;
 base1 & b1 = d;
 int result = b1.vfunc();
 return result;
} 

I actually expected this to do it for me, but instead the linker is giving me a bunch of vtable errors that I do not understand: ( Mac OS 10.6, gcc 4.2.1 )

$ gcc inheritance_tester.cc 
Undefined symbols:
  "vtable for __cxxabiv1::__vmi_class_type_info", referenced from:
      typeinfo for derivedin ccmeHq8C.o
  "___cxa_pure_virtual", referenced from:
      vtable for base1in ccmeHq8C.o
  "___gxx_personality_v0", referenced from:
      _main in ccmeHq8C.o
      base2::vfunc()     in ccmeHq8C.o
      derived::vfunc()     in ccmeHq8C.o
      base1::base1() in ccmeHq8C.o
      base2::base2() in ccmeHq8C.o
      derived::derived()in ccmeHq8C.o
      CIE in ccmeHq8C.o
  "vtable for __cxxabiv1::__class_type_info", referenced from:
      typeinfo for base1in ccmeHq8C.o
      typeinfo for base2in ccmeHq8C.o
ld: symbol(s) not found
+3  A: 

You need to override vfunc from base1. You can do it as follows:

class derived : public base1, public base2 {
public:
 using base1::vfunc;
 int vfunc() { return base2::vfunc(); } // call the other parent's vfunc
};
Kirill V. Lyadvinsky
Do you have a link to where this use of `using` is being described?
jdv
@jdv, §10.2/2 of the C++ Standard.
Kirill V. Lyadvinsky
@Kirill: thanks!
jdv
My experience is that method 2 works with our without the using base1::vfunc line. I'm not sure what that line is meant to accomplish.
NoahR
Ok, I have now run into the wisdom of Kirill. Without the using statement, other same-name vfunc overloaded members of base2 are hidden from the compiler. However, in derived, I had to use "using base2::vfunc;" not base1.
NoahR
A: 

This modified version of derived worked for me on Visual C++. Implication to me is that you have to disambiguate the two inherited vfunc()s explicitly.

class base1 {
public:
    virtual int vfunc() = 0;
};

class base2 {
public:
    int vfunc() { return 0;} //defined
};

class derived : public base1, public base2 {
public:
    int base1::vfunc() { return base2::vfunc(); } // call the other parent's vfunc
};

int main()
{
    derived d;
    base1 & b1 = d;
    int result = b1.vfunc();
    return result;
}
Steve Townsend
ld vtable errors reported in the second approach was due to calling gcc and not g++. Doh! First method still does not compile.
NoahR
+1  A: 

Your second piece of code is fine, you're just not compiling it correctly. You need to compile with g++, not gcc. When you compile with g++, it automatically links in the C++ runtime libraries; when you compile with gcc, it does not. You can also manually add them yourself:

# Option 1: compile with g++
g++ inheritance_tester.cc

# Option 2: compile with gcc and link with the C++ standard libraries
gcc inheritancet_test.cc -lstdc++
Adam Rosenfield
Thank you. This is a suitable solution to my problem and a fix for the method 2 that I posted.
NoahR