我可以在不使用new()的情况下实现工厂模式构造吗?

Can I implement Factory-pattern construction without using new()?

本文关键字:模式 工厂 实现 情况下 new 我可以      更新时间:2023-10-16

目前,我正在处理一个通过切换大小写实现多态性的令人愉快的遗留代码类:

class LegacyClass {
 public:
    enum InitType {TYPE_A, TYPE_B};
    void init(InitType type) {m_type=type;}
    int foo() {
        if (m_type==TYPE_A) 
        { 
            /* ...A-specific work... */
            return 1;
        }
        // else, TYPE_B:
        /* ...B-specific work... */
        return 2;
    }
    /** Lots more functions like this **/
  private:
    InitType m_type;
 };

我想将其重构为适当的多态性,例如:

class RefactoredClass {
 public:
    virtual ~RefactoredClass(){}
    virtual int foo()=0;
 };
 class Class_ImplA : public RefactoredClass {
 public:
    virtual ~Class_ImplA(){}
    int foo() {
        /* ...A-specific work... */
        return 1;
    }
 };
class Class_ImplB : public RefactoredClass {
 public:
    virtual ~Class_ImplB(){}
    int foo() {
        /* ...B-specific work... */
        return 2;
    }
 };

不幸的是,我有一个关键的问题:由于优化和体系结构的考虑,在LegacyClass的主要使用中,我不能使用动态分配;通过组合,实例是另一个类的成员:

 class BigImportantClass{
    /* ... */
  private:
    LegacyClass m_legacy;
 }

(在本例中,BigImportantClass可以动态分配,但分配需要在一个连续的虚拟段中,并且需要单个new()调用;我不能在BigImportantClass函数或随后的初始化方法中进一步调用new()

是否有一个好的方法来初始化一个具体的实现,多态的,不使用new() ?


到目前为止,我自己的进展是:我可以做的是提供一个char[]缓冲区作为BigImportantClass的成员,并在该内存中初始化一个RefactoredClass的具体成员。缓冲区足够大,可以容纳RefactoredClass的所有实现。然而,我不知道如何安全地做到这一点。我知道place -new语法,但我是处理对齐的新手(因此,c++ -FAQ警告我…),并且对RefactoredClass接口的所有具体实现进行通用对齐听起来令人望而生畏。是这条路吗?或者我还有其他选择吗?

下面是一些代码…只是做一些显而易见的事情。我没有使用c++ 11的新union特性,这实际上可能是一种更结构化的方式,以确保适当的对齐和大小,并清理代码。

#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);
    }
}

输出(带注释):

Impl_A(this 0018FF24)
Impl_A::f(x 5) n_ 10 -> 11
Impl_B(this 0018FF04)
Impl_B::f(x 5) n_ 20 -> 21.6667
Impl_B::f(x 6) n_ 21.6667 -> 23.6667
~Impl_B(this 0018FF14)           // x2 = a morphs type
Impl_A::f(x 7) n_ 11 -> 13       // x2 value 11 copied per a's above
~Impl_A(this 0018FF14)
~Impl_B(this 0018FF04)
~Impl_A(this 0018FF24)

我使用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;
}

现在应该有人回答了…这是我的

我建议使用字符数组和最大的整数类型之一的并集:

union {
    char refactored_class_buffer[ sizeof RefactoredClass ];
    long long refactored_class_buffer_aligner;
};

我还强烈建议使用assert甚至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

当你创建一个RefactoredClass时,你将它的fooStrategy设置为FooStrategyA::instance()