Template class inheritance

I have a problem with the following code fragment (this is a very simplified example that reproduces an error in my program):

#include <iostream> using namespace std; template<class T> class CBase { public: template <class T2> CBase(const T2 &x) : _var(x) {;} template <class T2> CBase (const CBase<T2> &x) {_var = x.var();} ~CBase() {;} T var() const {return _var;} protected: T _var; }; template<class T> class CDerived : public CBase<T> { public: template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;} template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;} ~CDerived() {;} }; int main() { CBase<double> bd(3); CBase<int> bi(bd); // <- No problem CDerived<double> dd1(3); CDerived<double> dd2(dd1); CDerived<int> di(dd1); // <- The problem is here return 0; } 

And the error is as follows:

 error: cannot convert 'const CDerived<double>' to 'int' in initialization 

How to solve this? (with the preference for changes in the base class, rather than in the derived class, and, if possible, without the use of virtuality)

Many thanks

EDIT: If I replace the corresponding line: CDerived<int> di(CBase<int>(CBase<double>(dd1))); It works, but it is not very practical ...

EDIT: It seems to solve the following:

 template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(static_cast<const CBase<T2>&>(x)) {;} 
+4
source share
2 answers
 CDerived<int> di(dd1); // <- The problem is here 

This calls the first CDerived constructor, so T2 is output as CDerived<double> , which is of type dd1 . Then dd1 becomes x in the constructor; x , which is a CDerived<double> , is passed to the constructor of the base class, which accepts int (which is the value of a template of type T to CDerived ). Therefore, an error because CDerived<double> cannot be converted to int . Note that T of CBase is int .

See how:

 CDerived<int> di(dd1); // <- The problem is here ^ ^ | | | this helps compiler to deduce T2 as double | this is T of the CDerived as well as of CBase 

If you want your code to work, do the following:

  • Publish first, not confidential.
  • Add another constructor that takes CDerived<T2> as a parameter.

So you need this:

 template<class T> class CDerived : public CBase<T> //derived publicly { public: template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;} //add this constructor template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(x.var()) {;} template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;} ~CDerived() {;} }; 

Now it should work: online demo

+5
source

Try creating another constructor that takes a common object in the base class and assigns a value using a dynamic cast.

 template <class T2> CBase (const Object &x) : _var() { try { const CBase<T2> &x_casted = dynamic_cast<const CBase<T2> &> (x); _var = x_casted.var(); } catch { std::cerr << "Object not of type CBase" << std::endl; } } 

Note. This may be considered a bad style. Runtime dynamic casting is more expensive than using virtual and overloading, so consider reorganizing your code.

0
source

Source: https://habr.com/ru/post/1414422/


All Articles