我有一个案例,我有一个指向基类的指针容器,其中一些指针实际上指向派生类的对象。我需要在容器中创建每个对象的副本,而不会在复制过程中将对象的派生“部分”切掉。
执行此操作的常用方法是实现类似“虚拟父克隆()”方法的操作。这要求层次结构中的每个类都使用自己的类型实现自己的clone()方法。这要求未来未写的子类实现父类所期望的行为,但无法强制执行。相反,我写了一个派生类可以继承的“适配器”类,而不是直接从基类继承。通过这样做,我可以在尚未写入的子类中强制执行一致性。
适配器类(层次结构中的中间级,父级和子级之间)确实需要了解子类,以便为正确的子类类型调用“new()”。这种“感觉”就像它有点违反了传统的面向对象模型,因为它让父母知道从中继承的类。但是,从通用编程的角度来看,这可能是合理的。它确实似乎编译和工作。
我正在寻找任何批评,需要注意的事项等。这些代码是否100%便携且符合标准?我可以使用更好的设计模式吗?这个适配器是否对其他人有用?谢谢,
肖恩
#include <cstdlib>
#include <iostream>
#include <stdio.h>
//-----------------------------------------
//Don't need to forward-declare bar; just needs to be defined before first instantiation
template<typename A, typename B>
class foo
{
public:
foo()
{
printf("foo::foo() : constructed a foo.\n");
}
virtual foo<A, B>* clone()
{
printf("foo::clone() : making a clone...\n");
return new foo<A, B>;
}
virtual void DoSomething()
{
printf("foo::DoSomething() : something...\n");
}
A myA;
B myB;
};
template<typename A, typename B, typename ChildClass>
class fooAdapter : public foo<A, B>
{
public:
fooAdapter()
{
printf("fooAdapter::fooAdapter() : constructed a fooAdapter.\n");
}
foo<A, B>* clone()
//or directly take in foo<>'s complete type rather than parametric per-parameter
{
return new ChildClass( *((ChildClass*) this) );
}
};
//-----------------------------------------
class bar : public fooAdapter<int, float, bar>
{
public:
bar()
{
printf("bar::bar() : constructed a bar.\n");
}
bar(const bar& myBar)
{
printf("bar::bar(bar) : copy-constructing a bar.\n");
}
virtual void DoSomething()
{
printf("bar::DoSomething() : something.\n");
};
//don't need to include clone() in bar
};
//-----------------------------------------
int main(int argc, char *argv[])
{
printf("About to construct myBar.\n");
bar myBar;
myBar.myA = 2;
myBar.myB = 1.5;
printf("\nAbout to clone myBar to fooTest.\n");
foo<int, float>* fooTest = myBar.clone();
fooTest->DoSomething();
printf("\nAbout to construct fooTest2 from fooTest.\n");
foo<int, float>* fooTest2 = new bar( *((bar*) fooTest) );
return EXIT_SUCCESS;
}
答案 0 :(得分:0)
停止使用哑指针。
使用cast-to-base操作或值ptr以及直接构造值ptr&#39的值的make值函数写入增强的any。
两者都知道对象的动态类型,并且因为他们拒绝自己指针,所以不太可能以多态方式创建。
template<class Base>
struct poly_any:private std::any{
Base* operator->(){ return to_base(*this); }
template<class X, std::enable_if<std::is_base_of<Base, std::decay_t<X>>{}, bool> =true>
poly_any(X&& x):
std::any(std::forward<X>(x)),
to_base([](std::any& self)->Base*{
return std::any_cast<std::decay_t<X>*>(&self);
})
{}
poly_any(poly_any const&)=default;
poly_any(poly_any &&)=default;
poly_any&operator=(poly_any const&)=default;
poly_any&operator=(poly_any &&)=default;
private:
using to_base_t = Base*(*)(std::any&);
to_base_t to_base=nullptr;
};
此poly_any<Base>
表示从Base
派生的任何类型的多态vallue类型。它需要一些工作,但这是它的核心。
我们不会要求任何人写clone
,我们会使用any
来键入擦除复制和自定义类型擦除转换为基础。
您仍然可以对此进行切片,但这是在您第一次将某些内容放入poly_any
时发生的。
std::any
,则可以写出,或者您可以使用boost::any
。可能存在拼写错误。