Here is a test code :
#include <iostream>
#define OPTION 1
template<typename T>
class Base
{
public:
Base() : _x()
{std::cout<<"Base()"<<std::endl;}
Base(const T& source) : _x(source)
{std::cout<<"Base(const T& source)"<<std::endl;}
Base(const Base<T>& source) : _x(source.x)
{std::cout<<"Base(const Base<T>& source)"<<std::endl;}
public:
inline void set(const T& source)
{std::cout<<"Base::set(const T& source)"<<std::endl;
this->_x = source;}
inline T get() const
{std::cout<<"Base::get(const T& source)"<<std::endl; return _x;}
protected:
T _x;
};
template<typename T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>()
{std::cout<<"Derived()"<<std::endl;}
Derived(const T& source) : Base<T>(source)
{std::cout<<"Derived(const T& source)"<<std::endl;}
Derived(const Derived<T>& source) : Base<T>(source)
{std::cout<<"Derived(const Derived<T>& source)"<<std::endl;}
public:
#if OPTION == 0
inline void set(const T& source)
{std::cout<<"Derived::set(const T& source)"<<std::endl;
this->_x = source;}
#endif
inline void set(const Base<T>& source)
{std::cout<<"Derived::set(const Base<T>& source)"<<std::endl;
this->_x = source.get();}
};
int main(int argc, char* argv[])
{
Derived<double> d;
double x = 4.5;
d.set(x);
return 0;
}
For me OPTION 0 and OPTION 1 would be equivalent but they are not and I would like to understand why.
With OPTION 0, when the main calls d.set(x) the compiler has the choice between Derived<T>::set(const T& source) and Derived<T>::set(const Base<T>& source) and of course, for T x he chooses Derived<T>::set(const T& source).
Now with OPTION 1, when the main calls d.set(x), I would think that the compiler has the choice between Base<T>::set(const T& source) and Derived<T>::set(const Base<T>& source).
But instead of choosing Base<T>::set(const T& source), the compiler (GCC 4.6.3 here) implicitely converts x to Base<T> and calls Derived<T>::set(const Base<T>& source).
Is it normal ?
And what is the common technique (if it exists) to avoid that (without changing the constructors) in order to have OPTION 0 and OPTION 1 equivalent ?
When overloading a function from a base class in a derived class, the base class function is hidden and never chosen by overload resolution unless a
usingdeclaration is used. That is, to allow the compiler to chooseBase<T>::set(const T&), you’d addedin your derived class.