【问题标题】:Class with both template and non-template constructor具有模板和非模板构造函数的类
【发布时间】:2013-08-26 05:38:39
【问题描述】:

我。问题描述:

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

  • Base1

  • Derived1

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

1BaseDerived 的构造是使用 Base 复制构造函数完成的。

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

二。可能的解决方案:

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 方法。我相信无论如何都有更好的解决方案。

三。什么不起作用:

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

    }

}

四。问题:

有没有在第二节中没有描述的有效方法来解决这个问题?

【问题讨论】:

  • Foo0..FooN 有共同点吗?
  • @Rapptz 一个通用算法构造来自其中任何一个。
  • 我认为这里缺少关键信息,即 Foo0..FooN 的构造会做什么。如果每种类型都会导致无法概括的自己的动作,那么使用模板毫无意义。实际上,您所说的蛮力将是正确的解决方案,因为它准确地定义了构造函数将使用哪些类型。模板只有在可以为全部或部分Foo0..FooN 推广的情况下才有意义。
  • @Kolyunya:那为什么还要在 II.2 中专门化模板构造函数呢?
  • @Kolyunya 2. Separating Base and Derived from others using typeid 为什么需要typeid?从BaseDerived(非模板)创建两个ctor,并为Foo 类创建一个模板。

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


【解决方案1】:

从你的cmets信息来看,Foo1FooN其实有一个共同点,都是socket地址的编码。所以在各种FooAny 类中进行to_string() 序列化,

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

【讨论】:

  • 替代方案可以使用 to_string 特征来实现它,如果您不喜欢,您不必添加此成员。
【解决方案2】:

你不需要在这里使用typeid

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

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

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

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

【讨论】:

  • 如果有机会在一个模板中进行从 Foo 1 到 Foo n 的构造,似乎没有理由不将 foo 基础和 foo 派生( 0 .. n )中的东西分开。如果这个答案是正确的解决方案,我无法真正理解 op 的问题。
【解决方案3】:

这是我的两分钱。 (Code 在 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多