C++ 我是否可以在不使用new()的情况下实现工厂模式构建?
目前,我正在处理一个令人愉快的遗留代码类,它通过开关大小写实现多态性:C++ 我是否可以在不使用new()的情况下实现工厂模式构建?,c++,initialization,factory-pattern,C++,Initialization,Factory Pattern,目前,我正在处理一个令人愉快的遗留代码类,它通过开关大小写实现多态性: class-LegacyClass{ 公众: 枚举初始化类型{TYPE_A,TYPE_B}; void init(InitType type){m_type=type;} int foo(){ if(m_type==类型A) { /*…特定工作*/ 返回1; } //否则,键入_B: /*…特定于B的工作*/ 返回2; } /**还有很多类似的功能**/ 私人: InitType m_类型; }; 我想将其重构为适当的多
class-LegacyClass{
公众:
枚举初始化类型{TYPE_A,TYPE_B};
void init(InitType type){m_type=type;}
int foo(){
if(m_type==类型A)
{
/*…特定工作*/
返回1;
}
//否则,键入_B:
/*…特定于B的工作*/
返回2;
}
/**还有很多类似的功能**/
私人:
InitType m_类型;
};
我想将其重构为适当的多态性,例如:
类重构类{
公众:
虚拟~RefacturedClass(){}
虚拟int foo()=0;
};
类\u ImplA:公共重构类{
公众:
虚拟~Class_ImplA(){}
int foo(){
/*…特定工作*/
返回1;
}
};
类\u ImplB:公共重构类{
公众:
虚拟~Class_ImplB(){}
int foo(){
/*…特定于B的工作*/
返回2;
}
};
不幸的是,我有一个关键问题:由于优化和架构方面的考虑,在主要使用LegacyClass
时,我不能使用动态分配;该实例是按组合划分的不同类的成员:
类BigImportantClass{
/* ... */
私人:
LegacyClass m_遗产;
}
(在本例中,BigImportantClass
可以动态分配,但分配需要在一个连续的虚拟段中,并且需要一个new()
调用;我不能在BigImportantClass
ctor或后续初始化方法中进一步调用new()
)
是否有一种不使用new()
而以多态方式初始化具体实现的好方法?
到目前为止,我自己的进展是:我能做的是提供一个
char[]
缓冲区作为bigmentrantclass
的成员,并以某种方式初始化该内存中的重构类的具体成员。缓冲区将足够大,可以容纳重构类的所有实现。然而,我不知道如何安全地做到这一点。我知道新语法的位置,但我不熟悉处理对齐(因此,被警告不要这样做),对于refacturedclass
接口的所有具体实现,一般地对齐听起来令人畏惧。这是路吗?或者我还有其他选择吗?现在应该有人回答了……这是我的
我建议使用字符数组的并集和最大的整数类型之一:
union {
char refactored_class_buffer[ sizeof RefactoredClass ];
long long refactored_class_buffer_aligner;
};
我还强烈建议使用断言,甚至是if(check)抛出;如果每种情况下的数据都相同,并且您只是在改变行为,您不需要在核心中进行分配-这基本上是一种使用单例策略的策略模式。最终在逻辑中使用多态性,而不是在数据中使用多态性
class FooStrategy() {
virtual int foo(RefactoredClass& v)=0;
}
class RefactoredClass {
int foo() {
return this.fooStrategy(*this);
}
FooStrategy * fooStrategy;
};
class FooStrategyA : public FooStrategy {
//Use whichever singleton pattern you're happy with.
static FooStrategyA* instance() {
static FooStrategyA fooStrategy;
return &fooStrategy;
}
int foo(RefactoredClass& v) {
//Do something with v's data
}
}
//Same for FooStrategyB
然后,当您创建一个RefacturedClass
时,将其FooStrategyA
设置为FooStrategyA::instance()
以下是一些代码。。。只是做一些显而易见的事情。我不使用,这实际上可能是一种更结构化的方法,可以确保适当的对齐和大小,并清理代码
#include <iostream>
template <size_t A, size_t B>
struct max
{
static const size_t value = A > B ? A : B;
};
class X
{
public:
X(char x) { construct(x); }
X(const X& rhs)
{ rhs.interface().copy_construct_at_address(this); }
~X() { interface().~Interface(); }
X& operator=(const X& rhs)
{
// warning - not exception safe
interface().~Interface();
rhs.interface().copy_construct_at_address(this);
return *this;
}
struct Interface
{
virtual ~Interface() { }
virtual void f(int) = 0;
virtual void copy_construct_at_address(void*) const = 0;
};
Interface& interface()
{ return reinterpret_cast<Interface&>(data_); }
const Interface& interface() const
{ return reinterpret_cast<const Interface&>(data_); }
// for convenience use of virtual members...
void f(int x) { interface().f(x); }
private:
void construct(char x)
{
if (x == 'A') new (data_) Impl_A();
else if (x == 'B') new (data_) Impl_B();
}
struct Impl_A : Interface
{
Impl_A() : n_(10) { std::cout << "Impl_A(this " << this << ")\n"; }
~Impl_A() { std::cout << "~Impl_A(this " << this << ")\n"; }
void f(int x)
{ std::cout << "Impl_A::f(x " << x << ") n_ " << n_;
n_ += x / 3;
std::cout << " -> " << n_ << '\n'; }
void copy_construct_at_address(void* p) const { new (p) Impl_A(*this); }
int n_;
};
struct Impl_B : Interface
{
Impl_B() : n_(20) { std::cout << "Impl_B(this " << this << ")\n"; }
~Impl_B() { std::cout << "~Impl_B(this " << this << ")\n"; }
void f(int x)
{ std::cout << "Impl_B::f(x " << x << ") n_ " << n_;
n_ += x / 3.0;
std::cout << " -> " << n_ << '\n'; }
void copy_construct_at_address(void* p) const { new (p) Impl_B(*this); }
double n_;
};
union
{
double align_;
char data_[max<sizeof Impl_A, sizeof Impl_B>::value];
};
};
int main()
{
{
X a('A');
a.f(5);
X b('B');
b.f(5);
X x2(b);
x2.f(6);
x2 = a;
x2.f(7);
}
}
我使用C++11联合实现了这一点。这段代码似乎在g++4.8.2下工作,但它需要-std=gnu++11或-std=c++11标志
#include <iostream>
class RefactoredClass {
public:
virtual ~RefactoredClass() { }; // Linking error if this is pure. Why?
virtual int foo() = 0;
};
class RefactorA : RefactoredClass {
double data1, data2, data3, data4;
public:
int foo() { return 1; }
~RefactorA() { std::cout << "Destroying RefactorA" << std::endl; }
};
class RefactorB : RefactoredClass {
int data;
public:
int foo () { return 2; }
~RefactorB() { std::cout << "Destroying RefactorB" << std::endl; }
};
// You may need to manually create copy, move, &ct operators for this.
// Requires C++11
union LegacyClass {
RefactorA refA;
RefactorB refB;
LegacyClass(char type) {
switch (type) {
case 'A':
new(this) RefactorA;
break;
case 'B':
new(this) RefactorB;
break;
default:
// Rut-row
break;
}
}
RefactoredClass * AsRefactoredClass() { return (RefactoredClass *)this; }
int foo() { return AsRefactoredClass()->foo(); }
~LegacyClass() { AsRefactoredClass()->~RefactoredClass(); }
};
int main (void) {
LegacyClass A('A');
LegacyClass B('B');
std::cout << A.foo() << std::endl;
std::cout << B.foo() << std::endl;
return 0;
}
#包括
类重构类{
公众:
virtual~refacturedClass(){};//如果这是纯链接错误。为什么?
虚拟int foo()=0;
};
类重构A:RefacturedClass{
双数据1,数据2,数据3,数据4;
公众:
int foo(){return 1;}
~RefactorA(){std::您是否可以将多态层次结构保持为某个环境类的私有,并且只在内部使用动态分配。如果您知道在BigImportantClass
构造函数之前需要哪个实现,您可能可以使用一个模板。@Wimmel:我正在考虑一个模板-那会很快!-但这意味着要拖动impl将校正选项提高到一个更可见的级别(BigImportantClass
变为BigImportantClass
)。但这绝对是一个选项。@Ziv您可以在工厂函数中隐藏实现选项,如CreateBigImportantClass()
,它甚至可以是静态成员。您确实意识到这一点,任何对小型函数的虚拟分派都可能比传统交换机慢得多?无论如何,不要放置char[]
在BigImportantClass
中,将LegacyClass
替换为嵌入对齐缓冲区的类。您可能可以使用double
和char[]的并集
-几乎没有什么比double
更需要对齐的了。替换类应该有一个函数来获取放置的引用或指针-新对象。+1-不错;-)“如果这是纯链接错误。为什么?”-当对象被销毁时,析构函数从大多数派生类运行回基类…销毁任何数据成员,将指向虚拟分派表的指针也设置回基类,以便不使用已销毁的派生类级别的重写。。。。
#include <iostream>
class RefactoredClass {
public:
virtual ~RefactoredClass() { }; // Linking error if this is pure. Why?
virtual int foo() = 0;
};
class RefactorA : RefactoredClass {
double data1, data2, data3, data4;
public:
int foo() { return 1; }
~RefactorA() { std::cout << "Destroying RefactorA" << std::endl; }
};
class RefactorB : RefactoredClass {
int data;
public:
int foo () { return 2; }
~RefactorB() { std::cout << "Destroying RefactorB" << std::endl; }
};
// You may need to manually create copy, move, &ct operators for this.
// Requires C++11
union LegacyClass {
RefactorA refA;
RefactorB refB;
LegacyClass(char type) {
switch (type) {
case 'A':
new(this) RefactorA;
break;
case 'B':
new(this) RefactorB;
break;
default:
// Rut-row
break;
}
}
RefactoredClass * AsRefactoredClass() { return (RefactoredClass *)this; }
int foo() { return AsRefactoredClass()->foo(); }
~LegacyClass() { AsRefactoredClass()->~RefactoredClass(); }
};
int main (void) {
LegacyClass A('A');
LegacyClass B('B');
std::cout << A.foo() << std::endl;
std::cout << B.foo() << std::endl;
return 0;
}