【问题标题】:Different classes that might be passed to constructor可能传递给构造函数的不同类
【发布时间】:2014-08-20 23:08:57
【问题描述】:

我的类的构造函数可以有两个不同的类传递给它。但是我无法提前知道它将是什么类型,因此我可以将其类型声明为数据成员以对其进行初始化。我如何知道将哪种对象传递给我的构造函数。最好我希望这样做没有 Boost。

我正在传递一个迭代器。它可以是 const 迭代器 (v.cbegin()) 或非常量 (v.begin()):

struct iterator
{
    iterator(IteratorType it)
        : m_it(it)
    { }
IteratorType m_it;
};

这是我调用构造函数的方式:

iterator X::begin()       { return iterator(x.begin()); }
iterator X::begin() const { return iterator(x.cbegin()); }

【问题讨论】:

  • 如果你不知道你会得到什么类型,你能用这些数据做什么?
  • 你能用模板吗? (假设两个类都有一个兼容的接口。)
  • @user3577210 您能否在问题中提供更多信息?
  • 如果它可以有两个不同的类传递给它,只需编写两个重载,这可能会委托给一个公共 ctor。无需过度设计。
  • 你为什么想知道?这取决于什么?当然你知道传递给你的函数的类型,所有参数都有一个类型。

标签: c++ stl


【解决方案1】:

您实际上并不想知道传递给您的 ctor 的参数类型,因为到那时该类已经在构建中,它的类型是一成不变的。

您想要的是根据参数决定使用哪个类,这需要早期干预。
不过,解决方案很简单:

使用工厂函数和模板类(<iterator> 和标准库的其他部分中有很多这种模式的示例)

template<class It>
struct myiterator
{
    myiterator(It it) : m_it(it) { }
private:
    typename std::iterator_traits<It>::type m_it;
    // The above will choke if It is not an iterator
};

template<class... X> auto make_myiterator(X&&.. x)
-> myiterator<typename std::decay<X>::type>
// Only the first arguments type is passed on.
{
    using just_making_sure_it_is_an_iterator =
        std::iterator_traits<typename std::decay<X>::type>::type;
    return {std::forward<X>(x)...};
}

【讨论】:

  • 我会在里面贴上typedef std::iterator_traits&lt;typename std::decay&lt;X&gt;::type&gt;::type just_making_sure_it_is_an_iterator;
  • 哦,我的意思是把它粘在身体里。你现在所拥有的,如果有人传递了std::string,他们会在调用行上得到“没有函数匹配那些参数”,这令人困惑。如果它在正文中,他们会在写有just_making_sure_it_is_an_iterator 的行上得到std::string 没有成员value_type。 (个人意见)
  • @MooingDuck:啊,我想多了。当然,没有必要在那里使用 SFINAE,并遭受由此产生的复杂错误消息。 (虽然有些地方我希望委员会对 SFINAE 更加热情,但请查看临时流的流提取/插入模板。)
【解决方案2】:

我通过使用 cmets 中建议的模板解决了这个问题:

template<typename It>
struct iterator
{
    iterator(It it) : m_it(it) { }
private:
    It m_it;
};

【讨论】:

    【解决方案3】:

    如果您的目标是确定您在班级中持有哪种类型,只需持有更“通用”的类型,那么您可以这样做:

    实现这两个类的一个通用接口类,并使用这个类型作为你的构造函数参数和属性。在您的界面中,设置一个方法协定,它返回您的类型(即字符串或枚举值等)。然后,在不同的实现中为这两个类实现这个方法。

    public class Iterateable
    {
      public:
        //Ctors/Dtors etc....
    
        //Pure virtual method.
        virtual string getType() = 0;
    
    
    }
    
    public class IteratorType1 : public Iterateable
    {
     public:
        //Ctors/Dtors etc....
    
        string getType {return "IteratorType1";}
    }
    
    public class IteratorType2 : public Iterateable
    {
      public:
        //Ctors/Dtors etc....
    
        string getType {return "IteratorType2";}
    }
    
    struct iterator
    {
        iterator(Iterateable it)
            : m_it(it)
        { }
    Iterateable m_it;
    };
    

    然后,您可以保存实现 Iterateable 接口的任何类型的对象。 然后,通过属性调用 getType() 可以确定类型,因为将调用在属性上保存的实例的大部分派生类上实现的方法(这是一种称为 late binding 的语言功能)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 2013-04-23
      • 2011-09-05
      • 1970-01-01
      • 2013-04-19
      • 1970-01-01
      • 2022-01-12
      相关资源
      最近更新 更多