Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;:通过'创建派生实例;扩展?';基本实例/实现向下转换? 我有一个C++类,它本质上是一个容器: class SimpleContainer { public: // Various accessor methods / iterators private: // The actual content }_C++ - Fatal编程技术网

C++;:通过'创建派生实例;扩展?';基本实例/实现向下转换? 我有一个C++类,它本质上是一个容器: class SimpleContainer { public: // Various accessor methods / iterators private: // The actual content }

C++;:通过'创建派生实例;扩展?';基本实例/实现向下转换? 我有一个C++类,它本质上是一个容器: class SimpleContainer { public: // Various accessor methods / iterators private: // The actual content },c++,C++,除了SimpleContainer,我还想创建一个StrictContainer,它通过对内容强制执行规则,在语义上扩展SimpleContainer,但使用与现有SimpleContainer实例相同的内容 class StrictContainer : public SimpleContainer { StrictContainer( const SimpleContainer& simple ) { // Check content in simple

除了
SimpleContainer
,我还想创建一个
StrictContainer
,它通过对内容强制执行规则,在语义上扩展
SimpleContainer
,但使用与现有
SimpleContainer
实例相同的内容

class StrictContainer : public SimpleContainer {

     StrictContainer( const SimpleContainer& simple ) {
         // Check content in simple, and raise an exception 
         // if it is not valid.
     } 
}
template<typename T, typename Container, typename Constraint>
class StrictContainer
{
public:
    StrictContainer(const Container& container = {}, Constraint constraint = {})
       : container_(container), constraint_(constraint)
    {
        validateAll();
    }

    StrictContainer(Container&& container, Constraint constraint = {})
        : container_(std::move(container)), constraint_(constraint)
    {
        validateAll();
    }

    // container interface ...
    void push_back(const T& value)
    {
        if(!constraint_(value))
            throw WhateverException();
        container_.push_back(value);
    }

private:
    void validateAll()
    {
        for(const auto& value : container_)
        {
            if(!constraint_(value))
                throw WhateverException();
        }
    }

    Container container_;
    Constraint constraint_;
 };
现在-我的问题是
SimpleContainer
StrictContainer
之间应该有什么样的关系:

is-a: 看起来很自然;这就是我在继承中指出的,但是接下来我将基于扩展
SimpleContainer
实例后构造创建一个
StrictContainer
实例-这可能吗

具有-a 或者,我可以将其实现为has-a关系,其中
StrictContainer
有一个
SimpleContainer
成员,但随后我需要在
StrictContainer
中再次实现所有访问器和迭代器,并转发到
SimpleContainer
实现

容器相当大;在创建
StrictContainer
时,我不会复制内容。我想我想要的是一种实现我自己的downcast操作符的方法:

SimpleContainer simple;
// Fill simpleContainer

{
    StrictContainer* strict = downcast<StrictContainer>( simple )
    ...
}  
SimpleContainer simple;
//填充简单容器
{
StrictContainer*strict=downcast(简单)
...
}  

如果
downcast
将调用
StrictContainer
上的方法来验证
简单输入参数的内容,那么is-a将是一场灾难。假设规则是
SimpleContainer
包含整数,
StrictContainer
只包含奇数整数

StrictContainer strict;
SimpleContainer simple;
strict.insert(1);  // OK value is odd
simple.insert(2);  // OK simple doesn't check oddness.
SimpleContainer& sc = strict;  // Reference to base.
sc.SimpleContainer::insert(2);  // Uh-oh.  That will use the simple container version
                                // of insert (even in the presence of virtual functions)
                                // and will insert an invalid even number into `simple`.

您需要has-a

因此,重申您的要求:

  • StrictContainer的接口与SimpleContainer的接口相同, 加上一些补充。(这意味着与 接口。)
  • 插入新的
    StrictContainer
    不需要 复制
    SimpleContainer
    内容。(这意味着使用句柄进行分解。)
假设原始的
SimpleContainer
的生存期跨越
StrictContainer
,这听起来像。所以,如果你愿意做一点分解——定义一个这样的接口怎么样

class MyInterface {
  // No contained state needed at all.
public:
  virtual ~MyInterface() {}
  virtual bool getThing1() const = 0;
  virtual int  getThing2() const = 0;
  // and so on...
};

class MyDecorator : public MyInterface {
    MyInterface &m_impl; // Could use a smart pointer, if available.
public:
    MyDecorator( MyInterface &impl ): m_impl(impl) {}
    bool getThing1() const override { return impl.getThing1(); }
    int  getThing2() const override { return impl.getThing2(); }
    // and so on...
};
然后你的具体实施:

class SimpleContainer : public MyInterface {
    bool m_thing1;
    int  m_thing2;
        ... // All the real state goes here.
public:
        ... // All the interface methods go here.
};
然后,
StrictContainer
是一个轻量级容器,它保留原始
SimpleContainer
的句柄,而不是完整副本

class StrictContainer : public MyDecorator {
    // Additional state, if needed.
public:
    StrictContainer( SimpleContainer &base ): MyDecorator(base) {}
    // Additional methods (like your additional validation method.
};
不需要特殊的“downcast操作符”,因为您已经需要调用
StrictContainer
的构造函数,并且它已经完成了所有需要的操作

SimpleContainer simple( ... );   // Construct as normal.
StrictContainer strict = simple; // Assuming no extra arguments needed.
很简单


是的,您需要在decorator类中为接口中的每个方法编写一次委托操作。但是您可以定义StrictContainer类的多个变体,而无需再次实现它们(除非您希望覆盖其中一些变体)。

我更喜欢使用适配器和策略(策略)模式的组合来实现类似的内容。您可以将StrictContainer(适配器)与完全保存数据的底层容器分离。非常类似于std::queue作为另一个容器(如vector)的适配器实现的方式。然后,您可以使用您想要的任何约束参数化StrictContainer适配器。无论何时向容器中添加元素,都会检查约束是否满足。如果是,则将元素添加到基础容器中,否则可以执行任何您喜欢的操作(例如保持容器不变或引发异常)

模板
类容器
{
公众:
StrictContainer(const-Container&Container={},Constraint={})
:容器(容器),约束(约束)
{
validateAll();
}
StrictContainer(容器和容器,约束={})
:容器(std::move(container)),约束(constraint)
{
validateAll();
}
//容器接口。。。
无效推回(常数T和值)
{
如果(!约束(值))
抛出WhateverException();
容器向后推(值);
}
私人:
void validateAll()
{
用于(常量自动和值:容器)
{
如果(!约束(值))
抛出WhateverException();
}
}
集装箱;;
约束约束;
};
然后可以像下面这样实例化StrictContainer:

StrictContainer<int, std::vector<int>, IsEvenConstraint<int>> myContainer;

myContainer.push_back(2);
myContainer.push_back(18);
myContainer.push_back(7); // throws
StrictContainer;
myContainer.向后推(2);
myContainer.向后推(18);
myContainer.向后推(7);//投掷
在本例中,StrictContainer使用std::vector作为数据存储,但您可以使用您喜欢的任何容器(如SimpleContainer)。然后可以像这样实现约束

template<typename T>
struct IsEvenConstraint
{
    bool operator()(const T& value)
    {
        return value % 2 == 0;
    }
};
模板
结构Iseven约束
{
布尔运算符()(常量T和值)
{
返回值%2==0;
}
};
根据您希望支持的容器类和约束,您可能需要相应地调整接口。使用可变模板,可以扩展StrictContainer以支持多个约束。也可以将lambda用于约束

auto lessThanOne = [](float f) { return f < 1.0f; };
StrictContainer<float, std::vector<float>, decltype(lessThanOne)> myContainer2(std::vector<float>{}, lessThanOne);
myContainer2.push_back(0.1f);
myContainer2.push_back(1.7f); // throws
auto-lessThanOne=[](float f){return f<1.0f;};
支原体2(std::vector{},lessThanOne);
支原体2.向后推(0.1f);
myContainer2.向后推(1.7f);//投掷

作为第三种选择,我建议采用基于策略的方法,如下例所示:

#include<vector>
#include<cassert>

template<typename T>
struct NoCheck {
    static bool isOk(T) {
        return true;
    }
};

template<typename T>
struct TheAnswer {
    static bool isOk(T t) {
        return false;
    }
};

template<>
struct TheAnswer<int> {
    static bool isOk(int t) {
        return t == 42;
    }
};

template<typename T, template<typename> class C = NoCheck>
struct SimpleContainer {
    bool add(T t) {
        if(C<T>::isOk(t)) {
            vec.push_back(t);
            return true;
        }

        return false;
    }

private:
    std::vector<T> vec{};
};

int main() {
    SimpleContainer<int> c1;
    assert(c1.add(42));
    assert(c1.add(0));
    SimpleContainer<int, TheAnswer> c2;
    assert(c2.add(42));
    assert(not c2.add(0));
}
#包括
#包括
模板
结构NoCheck{
静态布尔isOk(T){
返回true;
}
};
模板
s