C++ 指向抽象类型的指针数组

C++ 指向抽象类型的指针数组,c++,pointers,reference,virtual,abstract,C++,Pointers,Reference,Virtual,Abstract,我一直在试验抽象类型。 下面的代码给了我想要的效果 class base{ public: virtual void do_stuff() = 0; }; class derived: public base{ public: void do_stuff(){/*stuff*/} }; class manager{ vector<shared_ptr<base>> ptrs; public: void add(base* ptr){ ptrs.emplac

我一直在试验抽象类型。 下面的代码给了我想要的效果

class base{
public:
 virtual void do_stuff() = 0;
};

class derived: public base{
public:
 void do_stuff(){/*stuff*/}
};

class manager{
 vector<shared_ptr<base>> ptrs;
public:
 void add(base* ptr){
  ptrs.emplace_back(ptr);
 }
};

manager foo;
foo.add(new derived());
我尝试实现这一点的结果是:

class manager{
 vector<shared_ptr<base>> ptrs;
public:
 void add(base& ref){
  ptrs.emplace_back(&ref);
 }
};
类管理器{
向量PTR;
公众:
无效添加(基础和参考){
ptrs.安置后(&ref);
}
};
但是,编译器说,
没有已知的从“派生”到“基&”的转换。
。我不知道如何使对
base
的引用与对
derived
的引用兼容。我该如何解决这个问题?

通过
unique\u ptr
您的
add
函数拥有此对象的所有权。传递所有权的一种安全方式是传递
unique\u ptr

使用
unique\u ptr
非常灵活,因为您可以从
unique\u ptr
构建
共享的\u ptr
,或者如果您将来改变主意,您可以直接存储
unique\u ptr

class manager{
  vector<shared_ptr<base>> ptrs;
public:
  void add(std::unique_ptr<base> ptr){
    ptrs.emplace_back(std::move(ptr));
  }
};

manager foo;
foo.add(std::make_unique<derived>());
.

您可以让您的
add()
函数传递用于构造类型
T
的参数,其中
T
被指定为子类的类型

template <typename T, typename... TArgs>
void add(TArgs&&... args)
{
    ptrs.emplace_back(std::make_shared<T>(std::forward<TArgs>(args)...));
}
模板
无效添加(目标和参数)
{
ptrs.emplace_back(std::make_shared(std::forward(args)…);
}
可按如下方式调用:

bm.add<derived_a>( "hello" ); // derived_a constructor takes a string
bm.add<derived_b>( 42 );      // derived_b constructor takes an int
bm.add(“你好”);//派生\u构造函数接受字符串
bm.添加(42);//派生的_b构造函数接受int
完整示例

#include <string>
#include <vector>
#include <memory>

class base
{
public:
    virtual void f() = 0;
};

class derived_a : public base
{
public:
    derived_a( std::string const& s ) : s_{ s } {}
    void f() override { std::cout << "derived_a::string = " << s_ << '\n'; }

private:
    std::string s_;
};

class derived_b : public base
{
public:
    derived_b( int i ) : i_{ i } {}
    void f() override { std::cout << "derived_b::int = " << i_ << '\n'; }

private:
    int i_;
};

class base_manager
{
public:
    template <typename T, typename... TArgs>
    void add( TArgs&&... args )
    {
        ptrs.emplace_back( std::make_shared<T>( std::forward<TArgs>( args )... ) );
    }

    void print() { for ( auto& d : ptrs ) d->f(); }

private:
    std::vector<std::shared_ptr<base>> ptrs;
};

int main()
{
    base_manager bm;
    bm.add<derived_a>( "hello" );
    bm.add<derived_b>( 42 );
    bm.print();
}
#包括
#包括
#包括
阶级基础
{
公众:
虚空f()=0;
};
类派生的\u a:公共基
{
公众:
派生a(std::string const&s):s_{s}{

void f()override{std::cout您不能将临时(r值)传递给非常量引用。您还可以尝试获取该临时对象的地址,这最终将产生一个悬空指针和未定义的行为

假设要将未知运行时类型的对象传递给管理器:
您可以做的一件事是使用某种多态复制机制(如虚拟克隆方法)并在堆上创建对象的内部副本(它必须是多态的,以避免对象切片)


您最初的问题似乎关注这样一个事实,即用户/调用者创建了一个指针并将其交给他人,而从不删除它。我下面的示例只是向用户明确表示,他可以将其交给他人并将其忘记。换句话说,要求用户传递一个共享的\u ptr

#include <stdlib.h>
#include <vector>
#include <memory>

using namespace std;

class base{
public:
    virtual void do_stuff() = 0;
};

class derived : public base{
public:
    void do_stuff(){/*stuff*/ }
};

class manager{
    vector<shared_ptr<base>> ptrs;
public:
    void add(shared_ptr<base> ptr){
        ptrs.emplace_back(ptr);
    }
};

int main()
{
    manager foo;
    shared_ptr<derived> bp(new derived()); //require the user supply a smart pointer
    foo.add(bp);
    return 0;
}
#包括
#包括
#包括
使用名称空间std;
阶级基础{
公众:
虚拟void do_stuff()=0;
};
派生类:公共基{
公众:
void do_stuff(){/*stuff*/}
};
班级经理{
向量PTR;
公众:
无效添加(共享\u ptr ptr){
ptr.后侵位(ptr);
}
};
int main()
{
傅经理,;
shared_ptr bp(new-derived());//要求用户提供智能指针
foo.add(bp);
返回0;
}

这比其他帖子更简单,可能没有前瞻性,但它不需要派生类来实现额外的基成员。在许多情况下,这可能就足够了。

不要忘记在
base
中添加一个
virtual
析构函数。如果您的经理使用共享指针,为什么不将共享指针作为t
add
方法的参数?这很好,但它依赖于被添加的类型在编译时是已知的。通常对于多态类型,直到运行时才知道该类型。@ChrisDrew我理解,但我基于他调用
manager.add(派生()
)的示例,这意味着(从我的角度来看)他知道他要添加的类型。哇,我真的很喜欢这个结果。不幸的是,那里有很多不熟悉的代码,所以我必须先阅读一下,然后才能使用类似的东西。@WillyGoat在这种情况下,我建议你去:非常有趣。我可能会在我的项目中使用它。不像我希望的那样优雅,但是如果用户必须知道有指针,这不是世界末日。@WillyGoat我添加了另一个选项,调用者实际上不需要知道有任何指针。那太好了!我认为这不能用复制构造函数来完成,对吗?我猜当你尝试
重新部署时会遇到同样的问题(&base(obj))
?@Willy-Goat。你可以用一个复制构造函数来实现,但是在add方法中需要一个if-else语句来创建一个正确类型的副本。这也有一个缺点,每次你向项目中添加一个新类时,你还必须扩展if-elseif-。。statement@WillyGoat为供参考,该技术与其他技术密切相关与.Aah.相关。谢谢。我认为克隆方法是我目前首选的解决方案。@WillyGoat:实际上,这个模式有一个非常好的扩展,它不需要克隆方法,这在本次演讲中解释道:。它的优点是,它是非侵入性的,但管理器的内部变得相当复杂。也许我会更新我的稍后再回答。这比传递一个
唯一的\u ptr
更简单吗?如果传递一个
共享的\u ptr
,则会增加和减少
共享的\u ptr
上的引用计数的开销。另外,还不清楚
添加的
是否拥有所有权。
#include <string>
#include <vector>
#include <memory>

class base
{
public:
    virtual void f() = 0;
};

class derived_a : public base
{
public:
    derived_a( std::string const& s ) : s_{ s } {}
    void f() override { std::cout << "derived_a::string = " << s_ << '\n'; }

private:
    std::string s_;
};

class derived_b : public base
{
public:
    derived_b( int i ) : i_{ i } {}
    void f() override { std::cout << "derived_b::int = " << i_ << '\n'; }

private:
    int i_;
};

class base_manager
{
public:
    template <typename T, typename... TArgs>
    void add( TArgs&&... args )
    {
        ptrs.emplace_back( std::make_shared<T>( std::forward<TArgs>( args )... ) );
    }

    void print() { for ( auto& d : ptrs ) d->f(); }

private:
    std::vector<std::shared_ptr<base>> ptrs;
};

int main()
{
    base_manager bm;
    bm.add<derived_a>( "hello" );
    bm.add<derived_b>( 42 );
    bm.print();
}
class base {
public:
    virtual void do_stuff() = 0;
    virtual shared_ptr<base> clone() const = 0;
    virtual ~base()=default;
};

class derived : public base {
    int data;
public:
    derived() :data(0) {};
    derived(const derived& other) :data(other.data)
    {};
    virtual shared_ptr<base> clone() const override { 
        return make_shared<derived>(*this); 
    };
    void do_stuff() {/*stuff*/ }
};

class manager {
    vector<shared_ptr<base>> ptrs;
public:
    void add(const base& obj) {
        ptrs.emplace_back(obj.clone());
    }
};
int main() {
    manager foo;
    foo.add(derived());
}
void add(const base& obj) {
    if (typeid(obj)== typeid(derived) ){
        ptrs.emplace_back(make_shared<derived>(static_cast<const derived&>(obj)));              
    }
    else if (typeid(obj) == typeid(derived2)) { 
    ...         
}
#include <stdlib.h>
#include <vector>
#include <memory>

using namespace std;

class base{
public:
    virtual void do_stuff() = 0;
};

class derived : public base{
public:
    void do_stuff(){/*stuff*/ }
};

class manager{
    vector<shared_ptr<base>> ptrs;
public:
    void add(shared_ptr<base> ptr){
        ptrs.emplace_back(ptr);
    }
};

int main()
{
    manager foo;
    shared_ptr<derived> bp(new derived()); //require the user supply a smart pointer
    foo.add(bp);
    return 0;
}