PHOTOOG Photography writings by Olivier Giroux

4Oct/070

Unobvious inheritance issue (solution included)

I had these two classes with default constructors, copy constructors, and an additional templated constructor…

void Foo( /*a few overloads exist*/ );

struct Base {
  Base( ) {
  }
  Base( Base const& ) {
  }
  template< typename Param1 >
  Base( Param1 const& param1 ) {
    ::Foo( param1 );
  }
};

struct Derived : public Base {
  Derived( ) {
  }
  Derived( Derived const& other ) :
    Base( other ) {
  }
};

...and whenever I’d try to copy-construct a Derived I’d get a 5-page error dump about Foo not having an overload for a Derived argument.

Do you see how this happens? I’ve of course removed all the code that doesn’t matter here – for extra handicap imagine this was sprawling over a few KLOCs.

This issue here is how the compiler decides which is the “best” match among the constructor overloads. In theory the “best” is one that doesn’t require any type conversions, then if none are available, the one with the shortest conversion path. In the case of the Derived copy constructor, the Base templated constructor matches before the Base copy constructor because the Base copy requires an implicit conversion from Derived& to Base&.

Now if no conversions are necessary on both a templated and a non-templated method, the non-templated one is preferred. I needed to tell the compiler that the conversion was in fact desired.

To solve this I changed to…

Derived( Derived const& other ) :
  Base( static_cast< Base const& >( other ) ) {
}

…and then all was happy.

Now only after months of getting bugged by this and evading the issue... I’m glad it’s fixed.


Filed under: Uncategorized Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.