c++类,它可以容纳从一个公共类继承而来的一组类中的一个
C++ class that can hold one of a set of classes that all inherit from a common class
c++中如何处理拥有另一个类实例所有权的类,而该实例可能是继承自一个公共类的多个类的实例?
的例子:
class Item { //the common ancestor, which is never used directly
public:
int size;
}
class ItemWidget: public Item { //possible class 1
public:
int height;
int width;
}
class ItemText: public Item { //possible class 2
std::string text;
}
假设还有一个类Container
,每个类都包含一个Item,并且任何人对Item感兴趣的唯一时间是当他们将其从容器中取出时。我们也可以说,item只在Container创建的同时创建,目的是将它们放入Container中。
有哪些不同的构造方法?我们可以在Container中为所包含的Item创建一个指针,然后将参数传递给Container的构造函数,以确定要在哪种类型的Item上调用new,这样就可以将Item全部粘贴到堆中。是否有一种方法可以将Item与Container一起存储在堆栈中,这是否有任何优点?
如果Container和Items是不可变的,我们在创建时就知道它们的一切,并且永远不会改变它们,这有什么不同吗?
正确的解决方案如下:
class Container {
public:
/* ctor, accessors */
private:
std::unique_ptr<Item> item;
};
如果你有一个旧的编译器,你可以使用std::auto_ptr
代替。
智能指针确保容器严格拥有该项。(你也可以把它变成一个普通的指针,并卷起你自己的析构函数/赋值op/复制/移动/移动赋值op/等,但unique_ptr
已经完成了这一切,所以…)
为什么你需要在这里使用一个指针,而不仅仅是一个普通的组合?
因为如果你编写,那么你必须知道要编写的确切类。你不能引入多态性。所有Container
对象的大小必须相同,Item
的派生类的大小可能不同。
如果你迫切需要作曲呢?
那么你需要尽可能多的Container
变体,因为有存储的项目,因为每个这样的容器将是不同的大小,所以它是一个不同的类。你最好的机会是:
struct IContainer {
virtual Item& getItem() = 0;
};
template<typename ItemType>
struct Container : IContainer {
virtual Item& getItem() {
return m_item;
}
private:
ItemType m_item;
};
好吧,疯狂的想法。不要用这个:
class AutoContainer
{
char buf[CRAZY_VALUE];
Base * p;
public:
template <typename T> AutoContainer(const T & x)
: p(::new (buf) T(x))
{
static_assert(std::is_base_of<Base, T>::value, "Invalid use of AutoContainer");
static_assert(sizeof(T) <= CRAZY_VAL, "Not enough memory for derived class.");
#ifdef __GNUC__
static_assert(__has_virtual_destructor(Base), "Base must have virtual destructor!");
#endif
}
~AutoContainer() { p->~Base(); }
Base & get() { return *p; }
const Base & get() const { return *p; }
};
容器本身不需要动态分配,您只需要确保CRAZY_VALUE
足够大,可以容纳任何派生类。
下面的示例代码将编译并展示如何执行与您想要执行的操作类似的操作。这就是Java中所谓的接口。请注意,类中至少需要一些相似之处(在本例中是一个通用的函数名)。virtual关键字意味着所有子类都需要实现这个函数,并且无论何时调用该函数,实际调用的都是实类的函数。
类是否为const在这里没有害处。但一般来说,你应该尽可能地保持常量正确。因为如果编译器知道什么是不需要修改的,它可以生成更好的代码。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class outputter {
public:
virtual void print() = 0;
};
class foo : public outputter {
public:
virtual void print() { std::cout << "foon"; }
};
class bar : public outputter {
public:
virtual void print() { std::cout << "barn"; }
};
int main(){
std::vector<outputter *> vec;
foo *f = new foo;
vec.push_back(f);
bar *b = new bar ;
vec.push_back(b);
for ( std::vector<outputter *>::iterator i =
vec.begin(); i != vec.end(); ++i )
{
(*i)->print();
}
return 0;
}
输出: foo
bar
在容器类中保留一个指针(最好是智能指针),并在需要复制时调用由派生类实现的Item类的纯虚拟clone()
成员函数。您可以用一种完全通用的方式来完成此操作,例如:
class Item {
// ...
private:
virtual Item* clone() const = 0;
friend Container; // Or make clone() public.
};
template <class I>
class ItemCloneMixin : public Item {
private:
I* clone() const { return new I(static_cast<const I&>(*this); }
};
class ItemWidget : public ItemCloneMixin<ItemWidget> { /* ... */ };
class ItemText : public ItemCloneMixin<ItemText> { /* ... */ };
对于堆栈存储,您可以使用重载的new调用alloca()
,但这样做会有风险。只有当编译器内联了特殊的new操作符时,它才会起作用,你不能强迫它这样做(除非使用不可移植的编译器pragmas)。我的建议是,不值得为此而生气;运行时多态性属于堆。
- 如何从另一个文件继承私有成员变量和公共函数
- 为什么我不能在主函数之外定义一个类的对象(它继承了另一个类)?
- 如何定义一个没有重复代码的继承的 const 类成员函数?
- 在一个类中使用另一个类中的函数,而不在 c++ 中使用继承
- C++:返回一个基于范围 for 循环迭代器,其中包含继承对象
- 从抽象类继承以创建另一个抽象类时,我应该重新声明所有虚函数吗?
- 有没有办法C++将给定类的功能限制为仅另一个类(不使用继承,朋友)?
- 具有多个继承共享一个资源的对象 - 寻找良好的设计模式
- 一个关于继承和引用的C++问题
- 结交一个班友并继承它有什么用
- 继承:访问另一个类的私有和公共部分
- 如果一个类继承了一个带有虚拟 dtor 的类,为什么要删除一个没有虚拟 dtor 的类是可以的
- 相对于继承的构造函数,gcc 编译器是否还有一个错误?
- 如何创建一个继承自 std::vector 的类
- 动态创建一个继承的类,使用STD :: MAP使用基类指针访问
- C 预期的类名称{token,一个继承错误
- 如何创建一个继承自QWidget的qt插件
- 如何将"&player"对象传递到另一个继承的类构造函数("score")中?
- 是一个继承的默认构造函数,也是用户定义的
- 如何创建一个继承FILE方法的类