智能指针作为多态的类成员
Smart pointers as class members for polymorphism
我是智能指针的新手,如果有人能给我一个提示,我处理智能指针作为类成员的方式是否正确,我将非常感激。更准确地说,我想要实现的解决方案是在类多态性上下文中,并且应该是理想的异常安全的。
给定一个异构对象的容器(std::vector<shared_ptr<CBase> > my_vector
),通常添加元素的方法是:my_vector.push_back( shared_ptr<CBase>(new CChild(1)))
,这样以后就可以调用特定派生类的成员函数:my_vector[0]->doSomething()
.
-
我想要实现的是将堆栈对象添加到向量中,并且仍然能够做多态性。直觉上类似于:
CChild<float> obj1(1); my_vector.push_back(obj1)
。为了解决这个问题,我现在使用虚拟构造函数的习惯用法:CChild obj1(1); my_vector.push_back(obj1.clone());
.
注意,在some
的派生类中,我有创建对象的静态成员函数,例如:CChild<float> obj1 = CChild<float>::initType2(1);
-
因为需求问题,也有一个干净的接口,我现在有一个新的类
CFoo<T>
,作为数据成员CBase<T>
类的智能指针。
这个想法是除了包含其他新的私有成员,这个类封装/处理指向派生对象的智能指针,这样我就可以做这样的事情:
CFoo<float> myfoo(CChild<float>::initType2(1)); my_vector.push_back(myfoo);
。这意味着容器现在是vector<CFoo<T> >
类型而不是vector<shared_ptr<CBase> >
类型
在这种情况下,我想知道如何实现smart pointers
作为类成员的类的构造函数?那么遵循拷贝交换习惯的operator =
的实现如何呢?下面,我给出了我的类设计的一些插图:
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);
}
下面是我想直观实现的一个例子。首先,我用CFoo<float>
对象填充容器,这些对象除了包含另一个整数类成员外,还包含指向派生类的智能指针(注意,所有这些都只是举例说明)。
std::vector<CFoo<float> > my_bank;
for (int b=0; b < 3; b++){
float x = b*sqrt(2);
my_bank.push_back( new CFoo<float>( CChild1<float>::initType2(x), b) );
}
for (double s= 1.0; s<= 8.0; s *= 2.0){
my_bank.push_back( new CFoo<float>( CChild2<float>::initType2(x), 0) );
}
一旦容器被填满,我想做一些操作,调用virtual
函数,例如doSomething
,它在每个派生类中都是特化的。
for (int i=0; i < (int)my_bank.size(); i++){
int b = my_bank[i].m_nParam;
CBase<float>* myChild = my_bank[i].m_ptrBase;
myChild->doSomething( param1, param2, param3, ..., b);
}
我真的不知道如何处理这个问题。我对你列出的接口需求一半都不了解,所以把这当作一个实验答案,可能根本与你的问题无关。
我建议你告诉我我的方法到底缺少什么,我可以修改它。我现在将省略模板,因为它们似乎与问题无关。
那么,话不多说,最简单的开始使用智能指针的容器:
#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
用法:
int main()
{
BaseContainer v;
v.push_back(BasePtr(new DerivedB));
v.push_back(BasePtr(new DerivedC(true, 'a', Blue)));
BasePtr x(new DerivedA);
some_func(x);
x->foo()
v.push_back(x);
v.front()->foo();
}
如果你碰巧在某个地方有一个自动对象,你可以插入一个副本:
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();
}
Update:如果你想在构造之后初始化一个对象,你可以这样做:
{
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
};
用法:Base * b = new DerivedCar(DerivedCar::Porsche, true, 2000);
第三次更新:这个是不连接的,只是一个如何使用查找表来支持switch语句的说明。假设我们有许多相似的函数(相同的签名),我们希望基于某个整数使用它们:
struct Foo
{
void do_a();
void do_b();
// ...
void do(int n)
{
switch (n) {
case 2: do_a(); break;
case 7: do_b(); break;
}
}
};
我们可以在一个查找表中注册所有函数,而不是切换。这里我假设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 },
// ...
};
基本上,您将静态代码转换为容器数据。这总是一件好事。现在这很容易扩展;您只需在查找映射中添加新函数即可。不需要再碰实际的do()
代码! - 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 访问存储在向量C++中的结构的多态成员
- 运行时多态性 - 箭头运算符访问了错误的成员?
- 非虚拟基的多态成员类
- C++多态性:有没有办法找到对象成员函数的地址?
- 如果基类指针无法访问派生类成员函数,那么多态性有什么方便的呢?
- 无法从多态嵌套类访问包含类的成员
- C 多态性:允许模棱两可的成员类型
- 没有新成员的模板多态性派生类的大小
- 向上转换指向数据成员及其多态行为的指针
- 多态性:成员访问和吸气器给出不同的结果
- 如何在保持多态性的同时,将成员函数添加到需要它的继承类中,而不会影响其他同级类?
- 多态unique_ptr类成员
- 成员变量多态性
- 具有引用成员变量的多态性
- 使用反向引用移动多态成员的构造函数
- 将异步与多态成员函数一起使用
- 多态性:通过类文本或对象访问静态成员
- 多态成员变量
- 多态对象成员