A couple of C++ inheritance issues

Well, actually there’s only one issue (“Is this possible?”), but I have a couple different scenarios in mind. I’m not sure what the standard is, so I’ll use X -> Y to indicate that Y is a parent of X.

In the first case, you’ve got C -> B -> A, and A contains a pure virtual function foo(). Is it possible to require B and C to both provide unique implementations of foo()?

In the second case, you’ve got C -> B, A, and A contains a pure virtual function bar(). B contains an implementation of bar(). Is it possible to use B::bar() as C’s implementation without explicitly calling it?

Neither seems to be possible in Visual Studio .Net 2003. I suspect that the first is not compiler-dependent but the second is.

I think the answer is no to both cases, but I don’t have proof (so treat the rest as IMO).

The pure modifier just means that a derived class must have an implementation of this member function somewhere in its hierarchy - this could be the derived class itself or an ancestor. There isn’t any way to control exactly where in the hierarchy the member function is defined.

For case 1: If B defines it, then the compiler won’t require C to define it. However, it may be possible to do what you want manually by making the B::foo() also pure. [I’ll try this out after I post]

For case 2: B::bar() won’t resolve itself to A::bar() since B is not an ancestor of A. This is part of the rules to avoid collisions between A::bar() and B::bar() in general.

Making B::foo() pure, forces you to define C::foo(), but it prevents you from creating an instance of B. I don’t think this is what you wanted.

For reference:



#include <iostream>

class A
{
	public:
		virtual void foo() = 0;
};

class B : public A
{
	public:
		virtual void foo() = 0
		{
			std::cout << "B::foo" << std::endl;
			return;
		}
};

class C : public B
{
	public:
		virtual void foo()
		{
			std::cout << "C::foo" << std::endl;
			B::foo();
			return;
		}
};

void main()
{
//	B b;
//	b.foo();

	C c;
	c.foo();

	return;
}

Now that I’ve thought about it a little bit, I do see a solution to case 2. Just stick a class A’ in between A and C that has all the common elements from B that a child of A would need. It’s not particularly elegant, but it will work.

Case 1 is a bit more vexing. If you want to implement a clone() method that returns a deep copy of an object (which is where this came from), you really need every class in a heirarchy to have its own implementation. But I can’t see how to do that.

You could make sure a clone method was implemented for each class if you’re happy with runtime errors instead of compile-time errors.

This wasn’t my first idea, since RTTI is not guaranteed to be present on the project I’m working on: with a decent compiler and libraries, you will have run-time type information. In the clone method, you can create an object of your type and compare its typeid with the typeid of *this. It seems VC++ supports this, too.

A sample:


#include <typeinfo.h>

class A
{
public:
   virtual A * clone();

};

A * A::clone()
{
   A * pClone = new A();
   if (typeid(*pClone) != typeid(*this))
   {
      delete pClone;
      throw new Exception(); // however this works, it's been a while.
   }
   return pClone;
}

class B : public A
{
public:
   // Return A* to be consistent with A::clone() (I'm not sure this is necessary)
   virtual A * clone();
}

B * B::clone()
{
   B * pClone = new B();
   if (typeid(*pClone) != typeid(*this))
   {
      delete pClone;
      throw new ExceptionBadType(); // however this works, it's been a while.
   }
   return pClone;
}
// class C does not implement clone: very bad!
class C : public B
{
public:
   int foo () {return 0;}
}

int main(void)
{
   A * pA = new B();

// Works
   B * pB = dynamic_cast<B*>(pA->clone());

// Create our "bad" class
   C* pC = new C();

// Calling pC->clone() goes to B::clone(), which throws exception
   pA = pC->clone();
   return 0;
}


Any class in the inheritance chain will need to implement clone itself or an exception will be thrown by the class it inherits from. I suppose you’ll want a protected copy method that subclasses can call when doing a deep-copy.

If you don’t have access to typeid(), here’s another idea. For each class, have a member that defines what the class type is. When clone is called, have clone verify that the class type is the right type for the clone implementation.

Of course, this just pushes the implementation problem (unique implementation of the clone method) to the constructor, so each class would need a constructor that does the right thing. You might, however, be able to do something like this with the vft for each class.

For the second case: The using keyword does what you want. In the class C, simply say public: using B::bar; (no parentheses after bar). This brings B´s bar() into the scope as C, and if you call C´s bar(), instead B´s version will be used. This does not, however prevent you from also redefining bar() in C; if you do, C´s bar() will be used in the above scenario, even if there is the using statement; C´s implementation will hide B´s version with no warning whatsoever.

Correction:

This brings B´s bar() into the scope of C

using could work for the second case, but that was less of a concern, as having an implementation for A::bar() is compiler-enforceable. It really doesn’t look like there’s an option for case 1 that doesn’t rely on trusting the programmer to remember to do stuff.

To my knowledge, there is no way to do this with normal inheritance constructs (if I understand you correctly, you want some sort of “virtual, but every subclass has to provide it´s own implementation” mechanism). You could also look into private inheritance; then inherited methods become private regardless of their accessibility in the base class, and use the * using* keyword to make the ones you want to inherit unchanged explicitly public, or redefine them with the appropriate implemenation. Using public inheritance, LtningBug´s solution is IMO as close as you can get.

I know you asked the straight question “how can I do this”, and I don´t want to highjack this thread or get too opionated, but I don´t like solutions like the one LtningBug proposed. Sure, it works, but the problem you want to solve is a fundamental assumption of inheritance: if you inherit something, and don´t change it, then it also has to work in the subclass. If it doesn´t, redefine it.
The language just can´t enforce the semantics if you use C++´s inheritance. It´s the programmer´s responsibility. That´s true with every virtual method in C++; with deep_copy() it´s just more obvious, but methods like compare_to() have exactly the same problem.

Or consider the default operator overloading that C++ does behind your back. EVERY class that contains a pointer or reference and does not explicitly redifine the copy constructor or assignment operator (or even, to a lesser degree, ==) is a disaster waiting to happen, and there is absolutely no way to get around this. I dont´t see how this is different from clone(). Sorry for the rant.

clone() was recommended to me as the ideal method for making a deep copy of a heterogeneous list. That’s where the question originally came from.

IMHO, it is. But every class in the heterogeneous list has to have a suitable implemenation for clone(). My point was that C++ itself cannot guarantee that an inherited (or redefined) version of clone() has the proper semantics. But thinking about it, a “virtual but every subclass has to provide it´s own implementation” thing might be very useful, even if it only forces the programmer to simply implement it; it could prevent accidental inheritance of something that doesn´t work in a subclass.

I don´t know, however, of any language that does this, and it might be for a good reason. Like I said in my previous post, this problem is inherent with every virtual method and if you don´t want this behaviour, why use inheritance?

Because inheritance solves a lot of other problems. The clone() problem is just an unfortunate side effect.

Hmm… But this “side effect” is not specific to clone() and affects every single virtual method, even if the downsides are often not as obvious. This “side effect” is also the very essence of inheritance as it is implemented by C++. As I said, I don´t want to highjack this thread; maybe we could start a new thread in GD if we continue to disagree about that issue - why not?

Consider this: If a subclass doesn´t add any “elements” of it´s own, then inheriting the clone() method unchanged is perfectly safe, prevents redundant code and works as designed. If not, there is a problem. You seem to assume that only the clone() method needs to be redefined in a subclass, becuase it´s “more” unsafe than other methods. But every virtual method ist unsafe, because it can be inherited, and there is no way to enforce that the semantics hold in the subclass.