C ++,合适的数据模型,多态性

时间:2016-06-14 20:41:39

标签: c++ model polymorphism abstract-class

我正在寻找合适的数据模型。假设A是具有属性a的类,其具有简单的计算方法getat():

class A{       
  protected:
      int a;
  public:
      int getat(int t){return f(a,t);} //Some calculation
      virtual int getbt(int t)=0; //b defined in B, C
      virtual int getct(int t)=0; //c defined in C
      virtual ~A()=0; 
};

类似地,B,C是具有属性b,c的派生类(但C不是B的类型):

class B{       
  protected:
      int b;
  public:
      virtual int getbt(int t){return f(b,t);} //Some calculation
      virtual int getct(int t){return f(b,t)}; 
      virtual ~B(){}; 
};

class C{       
  protected:
      int b, c;
  public:
      virtual int getbt(int t){return f(b,t)};
      virtual int getct(int t){return g(c,t)};
      virtual ~C(){};
};

考虑到多态性,我想使用父类A的存储对象:

std::list <A>;   //Abstract class, impossible
std::list <A*>;  //Possible, but problem with the destructors
std::list<std::shared_ptr<A> >; //The best solution?

我的问题:

1]建议的具有纯虚函数的数据模型是否合理?

2]删除抽象是否有意义?

class A{       
  protected:
      int a;
  public:
      int getat(int t){return f(a,t);}
      int getbt(int t){}; 
      int getct(int t){}; 
}

随后,允许使用std :: list。

3]如果需要多态性,建议使用哪种方法存储A对象?

感谢您的帮助......

2 个答案:

答案 0 :(得分:1)

嗯......作文怎么样?

为了完整性,我已将句柄设为可复制

#include <utility>
#include <memory>
#include <vector>
#include <iostream>

int f(int a, int t) {
    return a * t;
}

struct has_a
{
    int a;
};

/// when some T is not derived from has_a, its getat method will return 0
template<class T, std::enable_if_t<not std::is_base_of<has_a, T>::value>* = nullptr>
int impl_getat(const T&, int t) { return 0; }

// when some T is derived from has_a, its getat method will return f(a, t)
template<class T, std::enable_if_t<std::is_base_of<has_a, T>::value>* = nullptr>
int impl_getat(const T& a, int t) { return f(a.a, t); }

// ditto for has_b
struct has_b
{
    int b;
};
template<class T, std::enable_if_t<not std::is_base_of<has_b, T>::value>* = nullptr>
int impl_getbt(const T&, int t) { return 0; }
template<class T, std::enable_if_t<std::is_base_of<has_b, T>::value>* = nullptr>
int impl_getbt(const T& b, int t) { return f(b.b, t); }

// ditto for has_c
struct has_c
{
    int c;
};
template<class T, std::enable_if_t<not std::is_base_of<has_c, T>::value>* = nullptr>
int impl_getct(const T&, int t) { return 0; }
template<class T, std::enable_if_t<std::is_base_of<has_c, T>::value>* = nullptr>
int impl_getct(const T& c, int t) { return f(c.c, t); }

// an object to hold the polymorphic model
struct handle
{
    // the concept that defines the operations on the model
    struct concept {
        // rule of 5 when virtual destructors are involved...
        concept() = default;
        concept(const concept&) = default;
        concept(concept&&) = default;
        concept& operator=(const concept&) = default;
        concept& operator=(concept&&) = default;
        virtual ~concept() = default;

        // cloneable concept
        virtual std::unique_ptr<concept> clone() const = 0;

        // concept's interface
        virtual int getat(int t) = 0;
        virtual int getbt(int t) = 0;
        virtual int getct(int t) = 0;
    };

    // a model models the concept, by deriving from any number of discrete parts
    template<class...Parts>
    struct model : concept, Parts...
    {
        model(Parts...parts)
        : Parts(std::move(parts))...
        {}

        model(const model&) = default;

        // model the clone op
        std::unique_ptr<concept> clone() const override {
            return std::make_unique<model>(*this);
        }

        // defer to impl functions (see above) for the calculations
        int getat(int t) override { return impl_getat(*this, t); }
        int getbt(int t) override { return impl_getbt(*this, t); }
        int getct(int t) override { return impl_getct(*this, t); }
    };


    std::unique_ptr<concept> _impl;

    // interface - note: not polymorphic, so we can be stored in a container
    int getat(int t) { return _impl->getat(t); }
    int getbt(int t) { return _impl->getbt(t); }
    int getct(int t) { return _impl->getct(t); }

    // constructor - construct from parts
    template<class...Parts>
    handle(Parts...parts)
    : _impl(std::make_unique<model<std::decay_t<Parts>...>>(std::move(parts)...))
    {
    }

    // let's make it copyable

    handle(const handle& r)
    : _impl(r._impl->clone())
    {
    }
    // rule of 5 because we meddled with the copy constructor...

    handle(handle&& r) : _impl(std::move(r._impl)) {}

    handle& operator=(const handle& r) {
        _impl = r._impl->clone();
        return *this;
    }

    handle& operator=(handle&& r) = default;


};

int main()
{
    std::vector<handle> v;
    v.emplace_back(has_a{10}, has_b{12});
    v.emplace_back(has_a{1}, has_b{2}, has_c {3});

    int aa = 1;
    for (auto& x : v)
    {
        std::cout << x.getat(aa) << std::endl;
        std::cout << x.getbt(aa) << std::endl;
        std::cout << x.getct(aa) << std::endl;
        std::cout << std::endl;
        ++aa;
    }

    // prove it's copyable etc

    auto y = v.back();
    std::cout << y.getat(aa) << std::endl;
    std::cout << y.getbt(aa) << std::endl;
    std::cout << y.getct(aa++) << std::endl;
    std::cout << std::endl;

    // and moveable

    y = handle(has_a{4}, has_b{5}, has_c{6});
    std::cout << y.getat(aa) << std::endl;
    std::cout << y.getbt(aa) << std::endl;
    std::cout << y.getct(aa++) << std::endl;
    std::cout << std::endl;

}

预期结果:

10
12
0

2
4
6

3
6
9

16
20
24

答案 1 :(得分:0)

如果默认实现在您的情况下没有意义,我更喜欢纯虚拟方法,这可以防止在编译时客户端滥用您的类,因此1考虑interface classes。 对于2,你应该注意到,如果你的客户没有覆盖什么是行为?运行时的消息,“请实现这个”...... 请详细说明3 ...