调用派生类的重写虚方法而不暴露它们

曼宁厄姆

我想编写一个函数,它以特定顺序f调用派生类的两个被覆盖的虚拟方法op_1和,而不会暴露这些方法以及方法的包含类。op_2f

我可以想到一些可行或几乎可行的方法,但我也是 C++ 新手,希望在常规性、可维护性等方面选择“最佳”方式的帮助:

  1. 创建一个按顺序调用虚拟操作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();
}
  1. 公开操作并公开非成员非朋友助手以按顺序调用它们。
/***** .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();
}
  1. 将操作保留为私有并公开一个友元函数以按顺序调用它们。
/***** .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 个同步操作:

  1. store.data_type<MyAppDataType>()将特定于应用程序的数据类型的表添加到商店。
  2. 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在简化的问题中,以下是映射到上述方法的方法:

  1. (映射到上面的#1)
/***** .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
}
  1. (映射到上面的#2)
/***** .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
}
  1. (映射到上面的#3)
/***** .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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

派生类调用父类的方法调用重写的虚方法调用错误的方法

在派生类中调用重写的方法

派生类的虚函数调用基类的虚函数

如何调用派生类(子类)的重写方法?

为什么基类指针指向基类中的纯虚方法而不是派生类中的重写方法?

在派生类中调用多个虚函数

派生类中的重写方法

从派生类对象访问重写的方法

在Java中,如何从派生类中的重写方法中调用基类的方法?

基类构造函数在Java中调用重写方法时派生类对象的状态

即使它们是私有的,基类的好友函数如何调用派生类的重写虚拟函数?(C ++)

ExpressionVisitor不访问派生类的重写属性

派生类调用父方法

如何调用派生类方法?

用派生类调用重载方法

调用派生类的非继承方法

派生类中的虚函数行为

C ++继承:使用派生类的实例调用基类的虚函数

Python。在不创建派生类的情况下覆盖方法,并调用原始方法

是否可以在派生类中重写静态方法?

C ++:用指向派生类的指针进行的虚函数调用是否仍具有vlookup

模板派生类中的错误“调用了纯虚函数”

通过派生类的实例在基础中调用纯虚函数

在C ++中从派生类的析构函数调用虚函数

C ++多态性:派生类调用基类虚拟函数,而不是重写的派生类

派生类不使用来自基类的所有纯虚方法

C ++继承:指向基类的派生类指针调用派生类方法

派生类指向基类对象的指针如何调用派生类的方法?

派生类不继承基类的重载方法