C++:如何实现多态对象创建器来填充表
我有一个可以用 set_num_col(int)
和 set_num_row(int)
调整大小的表格小部件对象.对这些函数中的每一个的调用都会调用 resize_table()
函数来用 table_cell
的对象填充小部件.但是,我有两种多态类型的单元格: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_cell
s 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
填充此地图,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 在 Table 的构造函数中生成初始单元格的示例.lambda所在的main
函数,使用方法见Table构造函数.
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 << "
";
}
}
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
相关文章