【发布时间】:2014-05-06 22:34:20
【问题描述】:
我的问题是关于编码风格和 C++ 中复杂表达式的分解。
我的程序有一个由类等组成的类组成的复杂层次结构。程序的许多对象都持有指向其他对象的指针或索引。有几个命名空间。正如我所说,它很复杂——我的意思是它是一个非常典型的 10,000 行 C++ 程序。
出现了规模问题。我的代码开始有很多不可读的表达式,比如p->a(b.c(r).d()).q(s)->f(g(h.i()))。 (就像我说的,它不可读。我看不下去了,而且是我写的!你可以看看它来抓住心情。)我试过重写这样的表达方式
{
const I ii = h.i();
const G &gg = g(ii);
const C &cc = b.c(r);
// ..
T *const qq = aa.q(s);
qq->f(gg);
}
所有这些局部作用域的符号可以说使代码更具可读性,但我承认我并不关心整体风格。毕竟,一些局部符号是const & 引用,而另一些则代表数据的副本。如果我不小心遗漏了& 之一,从而调用了一些大对象的不必要副本怎么办?我的编译器几乎不会警告我。
此外,带有本地符号的版本是冗长的。
这两种解决方案都不适合。在 C++ 中是否存在一种更惯用、更不易出错的方式来分解不可读的表达式?
插图
如果对问题的一个最小的、可编译的说明有帮助,那么这里就是一个。
#include <iostream>
class A {
private:
int m1;
int n1;
public:
int m() const { return m1; }
int n() const { return n1; }
A(const int m0, const int n0) : m1(m0), n1(n0) {}
};
class B {
private:
A a1;
public:
const A &a() const { return a1; }
B(const A &a0) : a1(a0) {}
};
B f(int k) {
return B(A(k, -k));
}
int main() {
const B &my_b = f(15);
{
// Here is a local scope in which to decompose an expression
// like my_b.a().m() via intermediate symbols.
const A &aa = my_b.a();
const int mm = aa.m();
const int nn = aa.n();
std::cout << "m == " << mm << ", n == " << nn << "\n";
}
return 0;
}
其他信息
我怀疑它是否与问题相关,但如果是:我的程序定义了几个模板,但目前不使用任何运行时多态性。
一个实际的例子
其中一位评论者请求我的代码提供一个实际示例。这里是:
bool Lgl::is_order_legal_for_movement(
const Mb::Mapboard &mb, const size_t ix, Chains *const p_chns1
) {
if (!mb.accepts_orders()) return false;
const Basic_mapboard &bmb = mb.basic();
if (!is_location_valid(bmb, ix, false)) return false;
const Space &x = mb.spc(ix);
if (!x.p_unit()) return true;
const size_t cx = x.i_cst_occu();
const Basic_space &bx = x.basic();
const Unit &u = x.unit();
const bool army = u.is_army();
const bool fleet = u.is_fleet();
const Order order = u.order();
const size_t is = u.source();
const Location lt = u.target_loc();
const size_t it = lt.i_spc;
const size_t ct = lt.i_cst;
// ...
{
const Space &s = mb.spc(is);
const Basic_space &bs = s.basic();
result = (
(army_s && (
bs.nbor_land(it) || count_chains_if(
Does_chain_include(ix), chns_s, false
)
)) || (fleet_s && (
// By rule, support for a fleet can name a coast,
// but need not.
ct == NO_CST
? is_nbor_sea_no_cst(bs, cs, it)
: is_nbor_sea (bs, cs, lt)
))
) && is_nbor_no_cst(army, fleet, bx, cx, it);
}
// ...
}
【问题讨论】:
-
您的示例代码符号名称对提高问题的可读性没有多大帮助。并使用函数而不是表达式链。
-
您的示例类可以轻松清理:只需使用
const并删除访问器。突然间,一切都变得不那么杂乱了。除此之外,简洁而有意义的名称总是有帮助的。 -
我真的希望您在实际代码中不要使用一个字母的变量名,因为这是示例行难以阅读的第一个原因。无论如何,我知道这不是答案,但这种表达方式可能是由于不尊重Law of Demeter - 这是非常不可取的。
-
看来您可能正在链接 getter 和 setter 的深层序列。也许您将类滥用为简单的“数据组”?
-
@Ke 或者认为“使用 OOP”意味着必须隐藏所有成员。