基类重载*运算符实现派生类复用及ProductFilter调用派生类方法问题
解决ISignalFilter派生类组合时的多态调用问题
你的问题核心是对象切片:当派生类对象被赋值给基类对象时,派生类的特有数据和虚函数表会被截断,导致ProductFilter中存储的a_和b_实际是基类实例,调用filtered_value时只会执行基类版本。要解决这个问题,必须通过指针或引用实现多态,这里推荐使用智能指针来自动管理内存。
修正后的完整代码
#include <iostream> #include <memory> using namespace std; template <typename T> class ISignalFilter; template <typename F> class ProductFilter; template <typename T> class ISignalFilter : public std::enable_shared_from_this<ISignalFilter<T>> { public: // 虚析构函数:确保派生类析构函数被正确调用 virtual ~ISignalFilter() = default; // 纯虚函数:强制派生类必须实现过滤逻辑 virtual T filtered_value(const T& value) = 0; // 重载*运算符:返回组合后的ProductFilter,使用智能指针传递对象 ProductFilter<T> operator*(std::shared_ptr<ISignalFilter<T>> other) { return ProductFilter<T>(this->shared_from_this(), std::move(other)); } }; template <typename F> class ProductFilter : public ISignalFilter<F> { public: // 构造函数:接收智能指针,避免对象切片 ProductFilter(std::shared_ptr<ISignalFilter<F>> a, std::shared_ptr<ISignalFilter<F>> b) : a_(std::move(a)), b_(std::move(b)) {} // 实现过滤逻辑:通过智能指针调用派生类的filtered_value F filtered_value(const F& value) override { return b_->filtered_value(a_->filtered_value(value)); } private: // 用智能指针存储基类对象,保持多态性 std::shared_ptr<ISignalFilter<F>> a_; std::shared_ptr<ISignalFilter<F>> b_; }; template <typename T> class IdentityFilter : public ISignalFilter<T> { public: T filtered_value(const T& value) override { return value; } }; int main() { // 使用shared_ptr创建派生类对象 auto filter1 = std::make_shared<IdentityFilter<int>>(); // 组合两个过滤器 auto filter2 = *filter1 * filter1; // 输出1,正确调用IdentityFilter的filtered_value std::cout << filter2.filtered_value(1) << std::endl; return 0; }
关键修改说明
- 虚析构函数:基类必须声明虚析构函数,否则通过基类指针销毁派生类对象时会触发未定义行为。
- 智能指针存储:用
std::shared_ptr<ISignalFilter<F>>替代直接存储基类对象,避免对象切片,同时自动管理内存。 - enable_shared_from_this:让基类继承该模板类,允许在成员函数
operator*中获取当前对象的shared_ptr,确保组合时传递的是正确的对象引用。 - 纯虚函数:将
filtered_value改为纯虚函数,强制所有派生类必须实现自己的过滤逻辑,避免意外调用基类的错误分支。
替代方案(使用原始指针)
如果不想用智能指针,也可以使用原始指针,但需要手动管理内存,注意避免内存泄漏:
// 修改ProductFilter的成员和构造函数 template <typename F> class ProductFilter : public ISignalFilter<F> { public: ProductFilter(ISignalFilter<F>* a, ISignalFilter<F>* b) : a_(a), b_(b) {} ~ProductFilter() override { // 注意:如果外部已经释放了指针,这里会重复释放,需要明确内存所有权 delete a_; delete b_; } F filtered_value(const F& value) override { return b_->filtered_value(a_->filtered_value(value)); } private: ISignalFilter<F>* a_; ISignalFilter<F>* b_; };
这种方式需要严格控制对象的生命周期,容易出错,因此更推荐智能指针方案。
内容的提问来源于stack exchange,提问作者Brian Yeh
相关产品推荐
相关产品推荐

