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

标签 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 对象的方法?

感谢您的帮助...

最佳答案

嗯……作文怎么样?

为了完整起见,我已经使句柄可复制

#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

关于C++,合适的数据模型,多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37821710/

相关文章:

c++ - 我有一个由 0's and 1' 组成的字符串。如何将二进制格式的 0's and 1' 存储在文件中?

ios - 如何使用外部数据源转换单元格类型

c# - 字符串解析为模型(RegEx 模型 Binder ?)

haskell - 使用 RankNTypes 编码的 System-F 自然数的 "case"运算符无法进行类型检查

c++ - Eigen,如何访问 MatrixBase<Derived> 的底层数组

c++ - 在 '{' 标记之前不允许在此处定义函数吗?

c++ - 有谁知道这个错误与什么有关?我检查了我的语法、我的声明,大部分内容,但找不到解决方案

mysql - 如何为模型中的所有选择查询定义默认 where 条件?

c++ - 通过接口(interface)检索未知类型数据的类型安全方法

java - 我可以将枚举作为变量传递和使用吗?