我想编写一个函数,它以特定顺序f
调用派生类的两个被覆盖的虚拟方法op_1
和,而不会暴露这些方法以及方法的包含类。op_2
f
我可以想到一些可行或几乎可行的方法,但我也是 C++ 新手,希望在常规性、可维护性等方面选择“最佳”方式的帮助:
f
的基类 ( ) 的公共非虚拟方法,并将操作设为私有。Base
/***** .h *****/
class Base {
virtual void op_1() const = 0;
virtual void op_2() const = 0;
public:
void f();
};
/***** .cpp *****/
void Base::f() {
op_1();
op_2();
}
/***** .h *****/
struct Base {
virtual void op_1() const = 0;
virtual void op_2() const = 0;
};
void f(const Base& b,) {
b.op_1();
b.op_2();
}
/***** .h *****/
class Base {
virtual void op_1() const = 0;
virtual void op_2() const = 0;
friend void f(const Base& b);
};
void f() {
b.op_1();
b.op_2();
}
#1 似乎很糟糕,因为派生类也可以访问f
,但它不是针对它们的意图或有用的,并且可能被滥用。
#2 解决了这个问题,但由于操作是公开的,因此封装较少。
#3 似乎解决了这两个问题,但我是 C++ 新手,对交友事物持冷淡态度——它似乎混淆了接口,我读过的指南(例如 Effective C++ #23)不鼓励在没有明确需要的情况下使用它。这是一个合适的案例吗?
#4 ???可能有更好的方法我看不到。开导我!
我需要在应用程序初始化时向 3rd 方数据存储注册一些数据类型 - 我需要按顺序执行 2 个同步操作:
store.data_type<MyAppDataType>()
将特定于应用程序的数据类型的表添加到商店。store.data_type<MyAppDataType>().member<MemberDataType>("member_name")
生成在步骤 1 中注册的特定于应用程序的数据类型,并设置其字段之一以与库的反射 API 一起使用 - 对于在非生产构建中进行调试很有用。操作#2 是可选的,但如果执行它应该发生在操作#1 之后。
我希望我的应用程序的各个模块 [1] 将自己的数据注册到商店,以避免出现一个大而杂乱的文件,其中应用程序的所有数据都注册在一起。为此,我在每个模块中包含一个扩展DataRegistrar
基类的类 - 基类强制派生类为上述两个操作提供特定于模块的实现:
struct DataRegistrar {
virtual void register_data_types(lib::store& store) const = 0;
virtual void setup_reflection(lib::store& store) const = 0;
};
在应用程序的其他地方,我可以有一些在应用程序启动时运行的代码,它按顺序为每个模块调用register_data_types
和。setup_reflection
在简化的问题中,以下是映射到上述方法的方法:
/***** .h *****/
class DataRegistrar {
virtual void register_data_types(lib::store& store) const = 0;
virtual void setup_reflection(lib::store& store) const = 0;
public:
void register_data(lib::store& store);
};
/***** .cpp *****/
void DataRegistrar::register_data(lib::store& store) {
register_data_types(store);
#if !PROD_BUILD
setup_reflection(store);
#endif
}
/***** .h *****/
struct DataRegistrar {
virtual void register_data_types(lib::store& store) const = 0;
virtual void setup_reflection(lib::store& store) const = 0;
};
void register_data(const DataRegistrar& module_registrar, lib::store& store) {
module_registrar.register_data_types(store);
#if !PROD_BUILD
module_registrar.setup_reflection(store);
#endif
}
/***** .h *****/
class DataRegistrar {
virtual void register_data_types(lib::store& store) const = 0;
virtual void setup_reflection(lib::store& store) const = 0;
friend void register_data(const DataRegistrar& module_registrar, lib::store& store);
};
void register_data(const DataRegistrar& module_registrar, lib::store& store) {
module_registrar.register_data_types(store);
#if !PROD_BUILD
module_registrar.setup_reflection(store);
#endif
}
[1] 应用程序的区域/目录/域中的“模块”,而不是 c++20 模块
让我们从#3开始:
friend
打破封装,这就是 Scott Meyers 不建议这样做的原因。我也不建议,除非你真的需要它。例如:CRTP 的私有构造 + 朋友技巧,以防止拼写错误。
我建议#1,因为所有工作都是由扩展 inerface 的类完成的DataRegistrar
。另外,您不希望其他人摆弄op_1()
and op_2()
。
如果使用自由函数,则要求实例有op_1()
和op_2()
被暴露,增加了被误用的机会。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句