C++;避免调用抽象基类';s构造函数 目前,我正在用C++(C++ 11标准)来构建一个库,我一直在努力弄清楚如何使我的设计更实用。我有以下抽象类E template<typename K> class E { public: virtual ~E() {}; virtual void init() = 0; virtual void insert(const K& k) = 0; virtual size_t count() const = 0; virtual void copy(const E<Key>& x) = 0; };

C++;避免调用抽象基类';s构造函数 目前,我正在用C++(C++ 11标准)来构建一个库,我一直在努力弄清楚如何使我的设计更实用。我有以下抽象类E template<typename K> class E { public: virtual ~E() {}; virtual void init() = 0; virtual void insert(const K& k) = 0; virtual size_t count() const = 0; virtual void copy(const E<Key>& x) = 0; };,c++,c++11,C++,C++11,和ETwo:public E,它类似于EOne。另外,还有一个不同的类J,它有一个成员std::vector,需要在构造过程中实例化: template<typename K> class J { public: J(size_t n, const E<K>& e) : v(n, e) {} private: std::vector<E<K>> v; } 但是,上面的代码没有编译,编译器抱怨我无法实例化抽

ETwo:public E
,它类似于
EOne
。另外,还有一个不同的类
J
,它有一个成员
std::vector
,需要在构造过程中实例化:

template<typename K>
class J
{
 public:
     J(size_t n, const E<K>& e) : v(n, e)
     {}
 private:
     std::vector<E<K>> v;
}
但是,上面的代码没有编译,编译器抱怨我无法实例化抽象类(我使用的是vc++但我相信在其他编译器上也会遇到同样的错误)。因此,我的问题是如何克服这个问题?你对我如何使我的设计更实用有什么建议吗

谢谢

因为
std::vector v
需要类E的静态实例化,它永远不会编译(正如您已经正确注意到的)。要使它发挥作用,应该使用

std::vector v

相反。它可以动态存储对象
EOne
ETwo
,同时可以使用类型为
E
的指针来引用它们。要向向量添加新对象,可以使用push_back:

v.push_back(std::make_shared<EOne<K>>{});
v.push_back(std::make_shared{});

要在类型之间转换,可以对智能指针使用动态和静态转换函数,例如
std::dynamic_pointer_cast()

有多种方法。下面的内容是最复杂、最合理的。它需要在类型定义中进行大量的工作,但会产生使用这些类型的最干净的“客户机”代码


现在是学习如何使字体规则的时候了

常规类型的实例的行为类似于值。C++算法和容器的工作方式比正则类型要好得多。
template<class K>
class E_interface {
public:
  virtual ~E_interface() {};
  virtual void init() = 0;
  virtual void insert(const K& k) = 0;
  virtual size_t count() const = 0;
  virtual void copy_from(const E_interface& x) = 0;
  std::unique_ptr<E_interface> clone() const = 0;
};
clone_ptr
是一个智能指针,它是一个
唯一的\u ptr
,知道如何通过调用存储对象上的
clone()
copy_from
来复制自身。它可能有一些拼写错误

现在我们写下我们的E:

template<class K>
class E {
  clone_ptr<E_interface<K>> pImpl;
public:
  E() = default;
  E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
  E( E const& )=default;
  E( E && )=default;
  E& operator=( E const& )=default;
  E& operator=( E && )=default;
  explicit operator bool() const { return (bool)pImpl; }

  void init() { if (*this) pImpl->init(); }
  void insert(const K& k) ( if (*this) pImpl->insert(k); }
  size_t count() const { if (*this) pImpl->count(); else return 0; }
};
给我们

template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
或者类似的



你的部分问题是你必须问自己“复制
E
意味着什么”。在C++中,你自己回答这个问题;根据您的回答方式,您可能被允许或不被允许将其存储在
std::vector

std::vector
是一个基于值的类中。
vector
没有意义,因为它将存储抽象类的值。“我想限制用户实例化它”-但是。。。编译器将为您这样做,因为纯虚拟函数-事实上,您甚至可以稍后在
clone()
函数中声明这一点,并且(智能)指针是您的朋友。
virtual void copy(const E&x)=0
多态副本是一罐您不想打开的蠕虫。避免。你有Java背景吗?为什么
shared\u ptr
?默认的go-to智能指针应该是
唯一的\u ptr
。这并不能回答以下问题:如何使用
n
副本
e
初始化
std::vector
e
常量&
?这确实是一个优雅(但有点复杂)的解决方案。然而,我相信你的最后一段是主要的外卖。显然,我可能只需要使用一个指向
E
的指针数组,并在其中存储
EOne
ETwo
对象就可以了。然而,这确实是一个复杂的问题,我目前无法具体回答(即,这是一个正在进行的项目)。但是,我要感谢您花时间和精力编译这个答案。@nick.katsip哑指针(原始指针)不适合放入
std::vector
s,因为
vector
s希望它们的内容能够以合理的方式移动,而且资源跟踪变得困难<代码>值\u ptr
尝试制作一个足够智能的指针,以便复制和移动
unique\u ptr
是一个只移动的指针(它不允许你复制10个副本)。那么,你建议我使用哪一个<代码>值\u ptr或
唯一\u ptr
?当我试图使用
unique\u ptr
并用
std::move()
将其提供给
std::vector::push\u back()
时,我遇到了一个错误,无法调用抽象类的构造函数。具体地说,在构造函数中,我将
v
更改为
std::vector
,在我得到一个
唯一的\u ptr p
对象之后,我做了
v.push_back(std::move(p))
。然后,编译器给我一个错误,我不能调用抽象类的构造函数。有什么建议吗?@nick.katsip您可以返回到一个唯一指针向量中,这意味着您的评论没有完全描述您的问题。试着画一个解决方案的草图,然后问一个新的问题,关于你所遇到的错误。一定要发一封信。
template<class T, class D=std::default_delete<D>, class Base=std::unique_ptr<T>>
struct clone_ptr:Base {
  using Base::Base;
  clone_ptr(Base&& b):Base(std::move(b)) {}
  clone_ptr()=default;
  clone_ptr(clone_ptr&&o)=default;
  clone_ptr(clone_ptr const& o):
    clone_ptr(
      o?clone_ptr(o->clone()):clone_ptr()
    )
  {}
  clone_ptr& operator=(clone_ptr&&o)=default;
  clone_ptr& operator=(clone_ptr const&o) {
    if (*this && o) {
      get()->copy_from(*o.get());
    } else {
      clone_ptr tmp(o);
      *this = std::move(tmp);
    }
    return *this;
  }
};
template<class K>
class E {
  clone_ptr<E_interface<K>> pImpl;
public:
  E() = default;
  E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
  E( E const& )=default;
  E( E && )=default;
  E& operator=( E const& )=default;
  E& operator=( E && )=default;
  explicit operator bool() const { return (bool)pImpl; }

  void init() { if (*this) pImpl->init(); }
  void insert(const K& k) ( if (*this) pImpl->insert(k); }
  size_t count() const { if (*this) pImpl->count(); else return 0; }
};
template<class Impl, class K>
struct E_impl: E<K> {
  using E<K>::E<K>;
  E_impl() : E<K>( std::make_unique<Impl>() ) {}
  template<class...Args>
  E_impl(Args&&...args) : E<K>( std::make_unique<Impl>(std::forward<Args>(args)...) ) {}
};
template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
J<std::string> j(10, std::make_unique<EOne<std::string>>(e))