C ++:如何实现多态对象创建器来填充表 [英] C++: How to implement polymorphic object creator to populate a table

查看:64
本文介绍了C ++:如何实现多态对象创建器来填充表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表小部件对象,可以用 set_num_col(int) set_num_row(int)调整大小.对这些函数中的每一个的调用都会调用 resize_table()函数,以使用 table_cell s对象填充小部件.但是,我有两种多态类型的单元格: table_cell_default table_cell_custom ,它们是从同一基类派生的.创建表后,考虑到客户端知道哪些单元格是自定义的,哪些是默认类型的,我如何用混合类型的单元格填充它?

I have a table widget object that can be resized with set_num_col(int) and set_num_row(int). A call to each of these functions will call a resize_table() function to populate the widget with table_cells objects. However, I have two polymorphic types of cells: table_cell_default and table_cell_custom, derived from the same base class. Upon creation of the table, how can I populate it with mixed types of cells, considering that the client knows which cells will be custom and which will be of default type?

我考虑过在表类中添加一个映射,并用 set_custom_cells(vector< index>())填充该映射,并使用 ij 索引单元格作为键,相应的lamda创建者返回正确的类型作为值,但是此映射将只用于填充表格一次,而不会再次使用.有没有一种更动态的方法,可以使用lambda作为table_cell创建器来更好地填充该小部件?

I thought about adding a map in the table class, and populate this map with for example set_custom_cells( vector<index>() ), with the ij indices of the cells as keys and the corresponding lamda creator returning the correct type as value, but this map will only be used once to populate the table and never again. Is there a more dynamic way, using a lambda as a table_cell creator to fill that widget in a better way?

谢谢

推荐答案

以下是使用 factory lambda 在表的构造函数中生成初始单元格的示例.请参阅lambda所在的 main 函数,以及如何使用该表的构造函数.

Here's an example of using a factory lambda to produce the initial cells in the Table's constructor. Refer to main function where the lambda is located, and the Table constructor for how it is used.

我不知道您的代码是什么样子,因此我只是将每个单元格包装到一个object_t中,然后将其放入表格中.

I do not know what your code looks like, so I just wrap each cell into an object_t and put that into the Table.

#include <cstdint>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

// Not idempotent.  Should be last include.
#include <cassert>

using std::cout;
using std::function;
using std::make_shared;
using std::move;
using std::ostream;
using std::shared_ptr;
using std::size_t;
using std::string;
using std::stringstream;
using std::vector;

namespace {

template <typename T>
void draw_right_justified(T const& x, ostream& out, size_t width) {
    stringstream ss;
    ss << x;
    string s = ss.str();
    size_t pad_width = s.length() < width ? width - s.length() : 1;
    out << string(pad_width, ' ') << s;
}

class object_t {
public:
    template <typename T>
    object_t(T x) : self_{make_shared<model<T>>(move(x))}
    { }

    friend void draw_right_justified(object_t const& x, ostream& out, size_t width) {
        x.self_->draw_right_justified_thunk(out, width);
    }

private:
    struct concept_t {
        virtual ~concept_t() = default;
        virtual void draw_right_justified_thunk(ostream&, size_t) const = 0;
    };

    template <typename T>
    struct model : concept_t {
        model(T x) : data_{move(x)} { }

        void draw_right_justified_thunk(ostream& out, size_t width) const {
            draw_right_justified(data_, out, width);
        }

        T data_;
    };

    shared_ptr<const concept_t> self_;
};

class Table {
    size_t col;
    size_t row;
    // data will be constructed with col_ * row_ entries.
    vector<object_t> data;
public:
    using object_factory = function<object_t(size_t, size_t)>;
    Table(size_t col_, size_t row_, object_factory& fn);
    auto operator()(size_t x, size_t y) const -> object_t;
    void display(ostream& out) const;
};

Table::Table(size_t col_, size_t row_, Table::object_factory& fn)
    : col{col_}, row{row_}
{
    data.reserve(col * row);
    for (size_t y = 0; y < row; ++y) {
        for (size_t x = 0; x < row; ++x) {
            data.emplace_back(fn(x, y));
        }
    }
}

object_t Table::operator()(size_t x, size_t y) const {
    assert(x < col);
    assert(y < row);
    return data[y * row + x];
}

void Table::display(ostream& out) const {
    auto const& self = *this;
    for (size_t y = 0; y < row; ++y) {
        for (size_t x = 0; x < col; ++x) {
            draw_right_justified(self(x, y), out, 8);
        }
        out << "\n";
    }
}

struct empty_t {};

void draw_right_justified(empty_t, ostream& out, size_t width) {
    string s = "(empty)";
    size_t pad_width = s.length() < width ? width - s.length() : 1;
    out << string(pad_width, ' ') << s;
}

struct bunny { string name; };

void draw_right_justified(bunny const& bunny, ostream& out, size_t width) {
    auto const& s = bunny.name;
    size_t pad_width = s.length() < width ? width - s.length() : 1;
    out << string(pad_width, ' ') << s;
}

} // anon

int main() {
    Table::object_factory maker = [](size_t x, size_t y) {
        if (x == 0 && y == 1) return object_t{bunny{"Bugs"}};
        if (x == 0 && y == 0) return object_t{empty_t{}};
        if (x == y) return object_t{string("EQUAL")};
        return object_t{x * y};
    };

    auto table = Table{3, 5, maker};
    table.display(cout);
}

输出...

 (empty)       0       0
    Bugs   EQUAL       2
       0       2   EQUAL
       0       3       6
       0       4       8

这篇关于C ++:如何实现多态对象创建器来填充表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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