C++类层次结构中跨类的布尔状态处理问题
问题描述
现有如下类层次结构:模板具体类A、模板抽象类B以及接口C,继承关系为 A <-- B <-- C。其中B声明了函数:
virtual std::optional<T> foo() const = 0;
C声明了函数:
virtual bar() = 0;
这两个函数均在A中完成了恰当的定义。
代码中存在一个B类型对象列表,会对其调用foo();同时存在一个C*指针列表,会对其调用bar()。
示例代码与需求
注:原示例代码存在语法错误,已修正(补充模板声明、函数返回值等)
template <typename T> class A : public B<T> { public: std::optional<T> foo() const override { /*...*/ }; void bar() override { /*...*/ }; // ... }; template <typename T> class B : public C { public: virtual std::optional<T> foo() const = 0; // ... }; class C { public: virtual void bar() = 0; };
需要为该类层次结构的对象添加一个布尔状态,具体需求如下:
- 需要一个布尔状态
m_isInteresting,属于整个类层次结构代表的对象。 - 由于解耦需求,不希望将
m_isInteresting放在A中。 - 调用
foo()时需将m_isInteresting设为true。 - 调用
bar()时需将m_isInteresting设为false。
已尝试方案
- 为C创建装饰器包装类,包含
m_isInteresting成员及相应访问器,转发bar()方法,在其中调用C的bar()并将m_isInteresting设为false,但无法将其设为true,因为foo()在下层类中。 - 尝试将
foo()的声明移至C(定义仍保留在A中),但因该函数返回std::optional<T>,而C并非模板类,派生类函数签名需与基类匹配,此方案难以实现。 - 考虑为B和C分别创建装饰器类,共享外部存储的
m_isInteresting,但此方案过于繁琐复杂。
解决方案
方案一:将状态放在顶层基类C中,通过保护接口修改
把状态放在最顶层的C类中,添加protected的状态修改方法,让下层类在实现对应函数时调用:
class C { protected: mutable bool m_isInteresting = false; void setIsInteresting(bool value) const { m_isInteresting = value; } public: virtual void bar() = 0; // 若外部需要访问状态,可添加getter bool isInteresting() const { return m_isInteresting; } }; template <typename T> class B : public C { public: virtual std::optional<T> foo() const = 0; // ... }; template <typename T> class A : public B<T> { public: std::optional<T> foo() const override { this->setIsInteresting(true); /*...原有逻辑...*/ }; void bar() override { this->setIsInteresting(false); /*...原有逻辑...*/ }; // ... };
mutable修饰符让const成员函数foo()也能修改状态,避免了const_cast的使用,同时状态属于整个对象,符合需求。
方案二:用Mixin类注入状态与行为
如果不想修改原有C类的定义,可以创建一个Mixin类,通过多重继承将状态和修改逻辑注入到类层次中:
class InterestStateMixin { protected: mutable bool m_isInteresting = false; void markAsInteresting() const { m_isInteresting = true; } void markAsUninteresting() { m_isInteresting = false; } public: bool isInteresting() const { return m_isInteresting; } }; // 修改B类,同时继承C和Mixin template <typename T> class B : public C, public InterestStateMixin { public: virtual std::optional<T> foo() const = 0; // ... }; template <typename T> class A : public B<T> { public: std::optional<T> foo() const override { this->markAsInteresting(); /*...原有逻辑...*/ }; void bar() override { this->markAsUninteresting(); /*...原有逻辑...*/ }; // ... };
这种方式无需改动原有C类,通过Mixin实现状态注入,同时满足解耦要求,状态不属于A类。
方案三:模板装饰器覆盖全接口
针对之前装饰器方案的缺陷,创建模板装饰器类,同时实现Bfoo()也能处理bar():
template <typename T> class DecoratedB : public B<T> { private: B<T>* m_wrapped; bool m_isInteresting = false; public: DecoratedB(B<T>* wrapped) : m_wrapped(wrapped) {} std::optional<T> foo() const override { m_isInteresting = true; return m_wrapped->foo(); } void bar() override { m_isInteresting = false; m_wrapped->bar(); } bool isInteresting() const { return m_isInteresting; } };
使用时将原Bfoo()还是通过C*调用bar()(DecoratedB
内容的提问来源于stack exchange,提问作者hexaquark
相关产品推荐
相关产品推荐

