克隆设计模式适配器-避免切片子对象(类似于原型模式) [英] Clone design pattern adapter - avoid slicing children (similar to prototype pattern)

查看:100
本文介绍了克隆设计模式适配器-避免切片子对象(类似于原型模式)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在某些情况下,我有一个指向基类的指针的容器,而其中一些指针实际上指向派生类的对象.我需要在容器中创建每个对象的副本,而不必在复制过程中切掉对象的派生部分".

I have a case where I have a container of pointers to a base class and some of those pointers actually point to objects of a derived class. I need to create copies of each of the objects in the container without slicing the derived "portions" of the objects off during the copying process.

执行此操作的一种常见方法是实现虚拟父级clone()"方法之类的方法.这要求层次结构中的每个类都使用自己的类型来实现自己的clone()方法.这就要求将来尚未编写的子类实现父类期望的行为,但无法强制这样做.相反,我编写了一个适配器"类,派生类可以从该类继承而不是直接从基类继承.通过这样做,我可以在尚未编写的子类中实现一致性.

A common way to do this is by implementing something like a "virtual Parent clone()" method. This requires every class in the hierarchy to implement its own clone() method using its own type. This requires that future yet-unwritten child classes implement behavior expected by the parent class, but with no way to enforce doing so. Instead, I wrote an "adapter" class that the derived classes can inherit from instead of directly inheriting from the base class. By doing this, I can enforce consistency in yet-unwritten child classes.

适配器类(父级和子级之间的层次结构中的中间级)确实需要了解子类,才能为适当的子类类型调用"new()".像这样的感觉"在某种程度上违反了传统的面向对象模型,因为它使父级具有从其继承的类的知识.但是,从一般的编程角度来看,这可能是有道理的.它似乎可以编译和工作.

The adapter class (intermediate-level in the hierarchy, between parent and child) does need to have knowledge of the child class in order to call "new()" for the proper child class type. This "feels" like it somewhat violates the traditional object-oriented model by making the parent have knowledge of classes that inherit from it. However, this may be justified from a generic programming perspective. It does seem to compile and work.

我正在寻找任何批评,需要注意的事情等.此代码是否100%可移植且符合标准?有没有我可以使用的更好的设计模式?此适配器对一般用途的其他人有用吗?谢谢,

I am looking for any critiques, things to watch out for, etc. Is this code 100% portable and standards-compliant? Is there a better design pattern that I could be using instead? Is this adapter useful to others for general purposes? Thanks,

塞恩

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

推荐答案

使用哑指针停止.

使用强制转换到基数的操作或值ptr以及可直接构造值ptr的值的make值函数编写增强型代码.

Write either an augmented any with a cast-to-base operation or a value ptr and a make value function that constructs the value ptr's value directly.

两者都知道对象的动态类型,并且由于它们拒绝采用指针本身,因此不太可能是多态创建的.

Both know the dynamic type of the object, and as they refuse to take pointers themselves are unlikely to be created polymorphically.

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 派生的任何类型的多态向量类型.它需要一些工作,但这就是它的实质.

this poly_any<Base> represents a polymorphic vallue type of any type derived from Base. It needs some work, but that is the meat of it.

我们不会要求任何人编写 clone ,我们使用 any 键入擦除复制和自定义类型擦除强制转换为基址.

We don't rewuire anyone to write clone, we use any to type erase copying and custom type erase cast-to-base.

您仍然可以对此进行切片,但是它是在您第一次将某些东西放入 poly_any 中时发生的.

You can still slice this, but it happens the first time you put something into the poly_any.

std :: any 可以编写,也可以使用 boost :: any .可能有错别字.

std::any can be written if you lack it, or you can use boost::any. There may be typos.

这篇关于克隆设计模式适配器-避免切片子对象(类似于原型模式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆