Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 智能指针作为多态性的类成员_C++_Templates_Stl_Polymorphism_Smart Pointers - Fatal编程技术网

C++ 智能指针作为多态性的类成员

C++ 智能指针作为多态性的类成员,c++,templates,stl,polymorphism,smart-pointers,C++,Templates,Stl,Polymorphism,Smart Pointers,我是智能指针新手,如果有人能给我一个提示,我作为类成员处理智能指针的方式是否正确,我将非常感激。 更准确地说,我想要实现的解决方案是在类多态性的上下文中,并且理想情况下应该是异常安全的 给定(std::vector my_vector),通常添加元素的方法是:my_vector.push_back(shared_ptr(new CChild(1)),这样以后,可以通过执行以下操作调用特定派生类的成员函数:my_vector[0]->doSomething() 我想要实现的是将堆栈对象添加到向量中

我是智能指针新手,如果有人能给我一个提示,我作为类成员处理智能指针的方式是否正确,我将非常感激。 更准确地说,我想要实现的解决方案是在类多态性的上下文中,并且理想情况下应该是异常安全的

给定(
std::vector my_vector
),通常添加元素的方法是:
my_vector.push_back(shared_ptr(new CChild(1))
,这样以后,可以通过执行以下操作调用特定派生类的成员函数:
my_vector[0]->doSomething()

  • 我想要实现的是将堆栈对象添加到向量中,并且仍然能够执行多态性。直觉上是这样的:
    CChild obj1(1);我的向量。向后推(obj1)
    。为了解决这个问题,我现在使用:
    CChild obj1(1);my_vector.push_back(obj1.clone())
    请注意,在我的一些派生类中,我有创建对象的静态成员函数,例如:
    CChild obj1=CChild::initType2(1)

  • 由于需求问题和干净的接口,我现在有了一个新类
    CFoo
    ,它的数据成员有一个指向
    CBase
    类的智能指针。
    除了包含其他新的私有成员, 这个类封装/处理指向派生对象的智能指针,这样我就可以做类似的事情:
    cfoomyfoo(CChild::initType2(1));my_向量。推回(myfoo)。这意味着容器现在是
    vector
    类型,而不是
    vector

  • 正是在这种情况下,我想知道如何将
    智能指针
    作为类成员实现类的构造函数?遵循复制交换习惯用法的
    操作符=
    的实现如何?下面,我对我的课堂设计做了一些说明:

    template < typename T >
    class CBase{
        public:
            CBase(){};
            virtual ~CBase(){};
            ...
            virtual CBase<T> * clone() const = 0;
            virtual CBase<T> * create() const = 0;
    };
    
    template < typename T >
    class CChild1 : public CBase{
        public:
            ...
            CChild1<T> * clone() const  { return new CChild1<T>(*this); }
            CChild1<T> * create() const { return new CChild1<T>(); }
            static CChild1 initType1(double, double);
            static CChild1 initType2(int);
    
    };
    
    template < typename T >
    struct type{
        typedef std::tr1::shared_ptr<T> shared_ptr;
    };
    
    template < typename T >
    class CFoo{
    
        public:
    
            CFoo();
            CFoo( const CBase<T> &, int = 0 );
            CFoo( const CFoo<T> & );
            void setBasePtr( const CBase<T> & );
            void swap( CFoo<T> & );
            CFoo<T> & operator = ( CFoo<T> );
            ...
            ~CFoo();
    
        private:
    
            typename type<CBase<T> >::shared_ptr m_ptrBase;
            int m_nParam;
    
    };
    
    template < typename T >
    CFoo<T>::CFoo()
        :m_nParam(0)
    // How shall I handle here the "m_ptrBase" class member? e.g point it to NULL?
    {
    
    }
    
    template < typename T >
    CFoo<T>::CFoo(const CBase<T> & refBase, int nParam)
        :m_ptrBase(refBase.clone()), // Is this initialization exception-safe?
        m_nParam(nParam)
    {
    
    }
    
    template < typename T >
    CFoo<T>::CFoo(const CFoo<T> & refFoo)
        :m_ptrBase(refFoo.m_ptrBase),
        m_nParam(refFoo.m_nParam)
    {
    
    }
    
    template < typename T >
    void CFoo<T>::setBasePtr( const CBase<T> & refBase ){
        // ??? I would like to do sth. like: m_ptrBase(refBase.clone())
    }
    
    template < typename T >
    CFoo<T>::~CFoo(){
        // The memory is going to be freed by the smart pointer itself and therefore
        // the destructor is empty, right?
    }
    
    template < typename T >
    void CFoo<T>::swap( CFoo<T> & refFoo ){
    //does this here makes sense?
        using std::swap;
    
        swap(m_ptrBase, refFoo.m_ptrBase);
        swap(m_nParam, refFoo.m_nParam);
    
    }
    
    template < typename T >
    CFoo<T> & CFoo<T>::operator = ( CFoo<T> copyFoo ){
        copyFoo.swap(*this);
        return (*this);
    }
    

    我真的不知道该怎么做。我不理解你列出的一半的接口要求,所以把这个看作是一个与你的问题无关的实验答案。

    我建议你告诉我我的方法到底缺少什么,我可以修改它。现在我将省略模板,因为它们似乎与问题无关

    因此,无需进一步ado,最简单的start使用智能指针容器:

    #include <vector>
    #include <memory>
    
    struct Base
    {
      virtual void f();
    };
    
    typedef std::shared_ptr<Base> BasePtr;
    typedef std::vector<BasePtr> BaseContainer;
    
    struct DerivedA : Base
    {
      virtual void f();
      // ...
    };
    
    // further derived classes
    
    如果您碰巧在某处有自动对象,可以插入副本:

    DerivedD d = get_some_d();
    v.push_back(BasePtr(new DerivedD(d)));
    
    要迭代:

    for (BaseContainer::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
    {
      (*it)->foo();
    }
    
    更新:如果要在构造后初始化对象,可以执行以下操作:

    {
      DerivedE * p = new DerivedE(x, y, z); 
      p->init(a, b, c);
      v.push_back(BasePtr(p));
    }
    
    或者,如果
    init
    函数是虚拟函数,则更简单:

    v.push_back(BasePtr(new DerivedE(x, y, z)));
    v.back()->init(a, b, c);
    
    第二次更新:以下是派生对象的外观:

    struct DerivedCar : Base
    {
      enum EType { None = 0, Porsche, Dodge, Toyota };
    
      DerivedCar(EType t, bool a, unsigned int p)
      : Base(), type(t), automatic_transmission(a), price(p)
      {
        std::cout << "Congratulations, you know own a " << names[type] << "!\n"; }
      }
    
    private:
      EType type;
      bool automatic_transmission;
      unsigned int price;
    
      static const std::unordered_map<EType, std::string> names; // fill it in elsewhere
    };
    
    代替开关,我们可以在查找表中注册所有函数。这里我假设C++11支持:

    struct Foo
    {
      // ...
      static const std::map<int, void(Foo::*)()> do_fns;
    
      void do(int n)
      {
        auto it = do_fns.find(n);
        if (it != do_fns.end()) { (this->**it)(); }
      }
    };
    
    const std::map<nt, void(Foo::*)()> Foo::do_fns {
      { 3, &Foo::do_a },
      { 7, &Foo::do_b },
    // ...
    };
    
    structfoo
    {
    // ...
    静态常数std::map do_fns;
    无效do(整数n)
    {
    auto it=do_fns.find(n);
    如果(it!=do_fns.end()){(this->**it();}
    }
    };
    const std::map Foo::do\u fns{
    {3,&Foo::do_a},
    {7,&Foo::do_b},
    // ...
    };
    

    基本上,您可以将静态代码转换为容器数据。这总是一件好事。这现在很容易扩展;您只需在查找映射中添加新函数即可。无需再次触摸实际的
    do()
    代码

    我不确定你最初的问题是否合理
    vector
    是一个拥有的容器,因此您不应该在容器中放置任何自动对象。为什么不先将元素添加到容器中,然后使用该元素代替原始的自动对象?否则,您总是可以插入一个副本:
    v.push_-back(shared_-ptr(new-Derived(obj))
    @KerrekSB,我不明白你的第一个建议
    先将元素添加到容器中
    ?你介意举例说明你的建议吗?至于
    复制插入
    派生(obj)
    到底是什么?我怎样才能添加一个使用
    静态函数成员创建的对象呢用x*/v做东西。推回(新的Foo(x))v.push_back(新Foo);Foo&x=v.back();/*现在使用x*/
    作为第二点,它的哪一部分不清楚?我只是直接复印。@KerrekSB,谢谢!对于第二点,假设我实例化了这样一个对象:
    CChild obj1=CChild::initType2(1)
    。我怎样才能遵循这种类型的实例化,直观地执行如下操作:
    v.push_back(shared_ptr(new CChild::initType2(1))
    ?好吧,我会让
    initType2
    返回一个共享指针,而不是一个裸指针。。。但更重要的是,我认为您可能根本不需要任何包装器类。我不知道它有多有用,也不知道它解决了什么问题,更简单的说是解决不了的。谢谢!这里有一些遗漏的东西:(1)在一些派生类中,我有一些
    init()
    函数用作某种构造函数。我需要它们,因为我有不同的方法来初始化具有相同数量和类型参数的对象,例如
    objB.init1(p1,p2);对象初始化2(p1,p2)init()
    类型,除非在构造函数上使用
    开关大小写,但我希望避免这种情况。第一个问题来了,考虑到初始化的类型,我如何才能做一些事情,比如
    v.push_back(BasePtr(new-DerivedC.init3(true'a',Blue))init
    函数转换为构造函数是否可行?其次,如果不是,那么对象是否可以以构造但未初始化的状态存在?(在这种情况下,我的使用示例已经介绍了如何处理这个问题。)为了解决这个问题,我想,我可以使用虚拟构造函数习惯用法来做:
    DerivedB objB;objB.init1(p1,p2);v、 推巴
    
    v.push_back(BasePtr(new DerivedE(x, y, z)));
    v.back()->init(a, b, c);
    
    struct DerivedCar : Base
    {
      enum EType { None = 0, Porsche, Dodge, Toyota };
    
      DerivedCar(EType t, bool a, unsigned int p)
      : Base(), type(t), automatic_transmission(a), price(p)
      {
        std::cout << "Congratulations, you know own a " << names[type] << "!\n"; }
      }
    
    private:
      EType type;
      bool automatic_transmission;
      unsigned int price;
    
      static const std::unordered_map<EType, std::string> names; // fill it in elsewhere
    };
    
    struct Foo
    {
      void do_a();
      void do_b();
      // ...
    
      void do(int n)
      {
        switch (n) {
          case 2: do_a(); break;
          case 7: do_b(); break;
        }
      }
    };
    
    struct Foo
    {
      // ...
      static const std::map<int, void(Foo::*)()> do_fns;
    
      void do(int n)
      {
        auto it = do_fns.find(n);
        if (it != do_fns.end()) { (this->**it)(); }
      }
    };
    
    const std::map<nt, void(Foo::*)()> Foo::do_fns {
      { 3, &Foo::do_a },
      { 7, &Foo::do_b },
    // ...
    };