@
GeruzoniAnsasu 这个隐含约定在这里不适用。这是给接口的用户看的,而这里实现和实现之间的关系是用户不应该可见的实现细节,所以其实无所谓。
甚至一般有经验的实现者会推荐 OP 的写法。因为这种写法最小化了内部实现和公共接口的依赖,维护者更容易划分出哪些(连续的)代码完全是实现细节,在一定程度上提高了实现内部的模块化,增加了可修改性。
内部实现故意去调用公开接口增加调用层次是不寻常的,特别是行为可能有差异。如:
class B
{
public: void f(){f_impl();}
private: virtual void f_impl(){/*...*/};
public:
void g1(){f();}
void g2(){f_impl();}
void g3(){B::f_impl();}
};
像 f_impl 就算是 private 也允许 override ,所以不是绝对意义上的内部实现。
而这里 g1 g2 g3 的含义就是不一样的。什么时候用什么得看你接口设计是拿来干什么的,而不是有一个教条。
在 B 的实现内部,如果硬要说考虑 f 或者 f_impl 应该怎么调用,那么尽量用 B::f_impl ,因为行为最确定;其次如果有要求允许 B 外的 overrider 就用 f_impl ,至少在 B 这个类内仍同属不可被类外访问的实现细节;最次才是用 f ,表示不同寻常的“就需要依赖外部接口”(此时通常还需要实现的注释)。
B 外要调用,当然是直接 f 了。如果需要在 B 外部 B::f_impl 或者 f_impl ,那这个就不该 private (名字也不该叫 _impl ),不过一般相当罕见。
你所谓的“重新调用 dispatch 的接口”还是“直接调用「你已经知道的那种情况的」具体流程”也应该看设计明确要支持的需求。如果设计不明就会出岔子。甚至极端点说,re-dispatching 这种形式本身就可能是可疑的伪需求。GCC 和 Clang 对 ELF symbol interposition 默认处理的不同就是这类岔子的一个现实例子,这时候就要扯皮了:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100937 。