具有模板和非模板构造函数的类

时间:2013-08-23 08:28:24

标签: c++ class inheritance c++11 constructor

予。问题描述:

班级Derived是班级Base的孩子。您无法修改班级Base。为Derived定义构造函数和赋值运算符,以便可以从以下实例构造它:

  • Base 1

  • Derived 1

  • N非多态且不相关的类型Foo1,...,FooN 2

1 使用Base复制构造函数完成DerivedBase的构建。

2 所有Foo1,...,FooN的构建都是通用算法完成的。

II。可能的解决方案:

1。蛮力:

N+1单独的构造函数+ N+1单独的赋值运算符。绝对不优雅。大量无用的代码:N+1方法声明在源头中的头+ + N+1方法实现中。未使用模板的强大功能。

2。具有类型限制的模板构造函数

声明并定义常规拷贝构造函数

Derived::Derived ( const Base& object_reference ) { ... }

声明模板构造函数:

template<typename type>
Derived::Derived ( const type& object_reference );

Foo0,...,FooN

中的每一个实施
template<>
Derived::Derived<Foo0> ( const Foo0& object_reference ) { ... }

...

template<>
Derived::Derived<Foo9> ( const Foo9& object_reference ) { ... }

因此,标头只包含两个构造函数,只包含两个赋值运算符。但是我们必须在源代码中实现N+1方法。我相信无论如何都有更好的解决方案。

III。什么行不通:

1。使用`dynamic_cast`

将`Base`和`Derived`与其他人分开
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`

}

2。使用`typeid`

将`Base`和`Derived`与其他人分开
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

    }

}

IV。问题:

是否有任何有效的方法(第二节没有描述)来解决问题?

3 个答案:

答案 0 :(得分:1)

根据评论中的信息,Foo1FooN之间实际上存在共性,即它们都是套接字地址的编码。因此,在各种to_string()类中进行FooAny序列化,

class FooAny // Any runs from 1 to N
{
public:
    std::string to_string() const { /* FooAny specific */ }
private:
    // bla
};

然后在Derived中使用一个模板构造函数,该构造函数委托给一个std::string参数的常规构造者

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
};

答案 1 :(得分:1)

您无需在此处使用typeid

2. Separating `Base` and `Derived` from others using `typeid`

为Foo类制作两个非模板ctors和一个模板ctor:

class Derived : public Base {
 public:
  Derived(const Derived&);
  Derived(const Base&);

  template<class Foo>
  Derived(const Foo&);
};

答案 2 :(得分:1)

这是我的两分钱。 (Ideone.com上的Code

#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);
}