Reputation: 6230
Class Derived
is a child of class Base
. You can not modify class Base
. Define constructors and assignement operators for Derived
so that it could be constructed both from instances of:
Base
1
Derived
1
N
non-polymorphic and not related types Foo1
, ... , FooN
2.
1 Construction from both Base
and Derived
is done using Base
copy constructor.
2 Construction from all of Foo1
, ... , FooN
is done by a generic algorithm.
N+1
separate constructors + N+1
separate assignment operators. Absolutely not elegant. Tons of useless code: N+1
methods declarations in header + N+1
methods implementations in source. Power of templates not used.
Declare and define regular copy-constructor
Derived::Derived ( const Base& object_reference ) { ... }
Declare template constructor:
template<typename type>
Derived::Derived ( const type& object_reference );
Implement for each of Foo0
, ... , FooN
template<>
Derived::Derived<Foo0> ( const Foo0& object_reference ) { ... }
...
template<>
Derived::Derived<Foo9> ( const Foo9& object_reference ) { ... }
As a result the header will contain only two constructors and only two assignment operators. But we will have to implement N+1
methods in the source. I believe there is a better solution anyway.
template<typename type>
Derived::Derived ( const type& object_reference )
{
// This line will not compile since `Foo0`, ... , `FooN` are non-polymorthic
Base* base_ptr = dynamic_cast <Base*> (&object_reference);
if ( base_ptr != nullptr )
{
// Construct from `Base`
return;
}
// Construct from `Foo0`, ... , `FooN`
}
template<typename type>
Derived::Derived ( const type& object_reference )
{
if
(
typeid(typename) == typeid(Foo0)
||
...
||
typeid(typename) == typeid(FooN)
}
{
// Construct from `Foo0`, ... , `FooN`
return;
}
else
{
// Construct from `Base`
// Here we should call `Base` members which `Foo0`, ... , `FooN` don't have
// so the following line will not compile
// object_reference.some_method();
// And we need to cast "&object_reference" to "Base*" what is not possible
// because `Foo0`, ... , `FooN` are not polimorthic
}
}
Is there any efficient way, which is not described in section II, to solve the problem?
Upvotes: 2
Views: 1032
Reputation: 3918
Here is my two cents. (Code on Ideone.com)
#include <iostream>
#include <type_traits>
namespace so
{
struct _base_ {};
struct _foo1_{};
struct _foo2_{};
struct _foo3_{};
class _derived_: public _base_
{
public:
_derived_() = default;
_derived_(_derived_ const & _obj)
: _base_(_obj)
{
std::cout << "Constructed from _derived_" << std::endl;
}
_derived_(_base_ const & _obj)
: _base_(_obj)
{
std::cout << "Constructed from _base_" << std::endl;
}
template <typename _t_, typename = typename std::enable_if<
std::is_same<_t_, _foo1_>::value || std::is_same<_t_, _foo2_>::value ||
std::is_same<_t_, _foo3_>::value>::type>
_derived_(_t_ const &)
: _base_()
{
std::cout << "Constructed from _fooN_ using generic algorithm" << std::endl;
}
~_derived_() noexcept (true) = default;
};
} //namespace so
int main()
{
so::_base_ b_{};
so::_derived_ d_{};
so::_foo1_ f1_{};
so::_foo2_ f2_{};
so::_foo3_ f3_{};
so::_derived_ db_{b_};
so::_derived_ dd_{d_};
so::_derived_ df1_{f1_};
so::_derived_ df2_{f2_};
so::_derived_ df3_{f3_};
return (0);
}
Upvotes: 1
Reputation:
You don't need to use typeid
here:
2. Separating `Base` and `Derived` from others using `typeid`
Just make two non-template ctors and one template ctor for Foo classes:
class Derived : public Base {
public:
Derived(const Derived&);
Derived(const Base&);
template<class Foo>
Derived(const Foo&);
};
Upvotes: 1
Reputation: 70506
From the information in your comments, there actually is a commonality between Foo1
and FooN
, namely they are all encodings of a socket address. So make a to_string()
serialization in the various FooAny
classes,
class FooAny // Any runs from 1 to N
{
public:
std::string to_string() const { /* FooAny specific */ }
private:
// bla
};
and then use a single template constructor in Derived
that delegate to a regular construtor taking a std::string
argument
class Derived
{
explicit Derived(std::string const& s): /* convert data members from string */ {}
template<class Foo>
explicit Derived(Foo const& f): Derived(f.to_string()) {} // delegating constructor
};
Upvotes: 1