重载基类函数是否属于不良编程实践?附C++代码场景示例
嘿,这个问题问得很到位——这种重载方式本身完全不是不良编程实践,甚至是利用派生类特性做优化的合理操作,但你的代码里存在几个关键问题得修正,同时得搞清楚重载的静态绑定特性带来的行为差异。
先明确:你这是「重载」,不是「覆盖」
你在SortedRange里写的bool disjoint(const SortedRange &other) const是对基类disjoint(const MySet &other) const的重载(overload)——因为参数类型不一样,和虚函数的「覆盖」(override)不是一回事,覆盖要求参数列表完全一致,而且基类函数得是虚函数。
另外,你加的using MySet::disjoint;这步太对了!它能防止派生类的同名函数把基类版本给隐藏了,这样用SortedRange对象的时候,既能调用针对同类型的高效版本,也能调用处理通用MySet的版本,不会出现调用不上基类函数的坑。
你的实现逻辑:合理但有代码错误
1. 合理的地方
SortedRange是有序区间嘛,用首尾边界判断两个区间是否不相交(set.front() > other.set.back() || other.set.front() > set.back()),这比基类遍历整个集合快多了——时间复杂度直接从O(n)降到O(1),这种针对派生类特性做的重载优化,完全符合设计意图,非常合理。
2. 必须改的代码问题
你的代码现在编译都过不了:基类MySet里的set是私有成员(C++里类成员默认是private),派生类SortedRange根本没法直接访问它。要解决这个,有两个办法:
- 把
set的访问权限改成protected,让派生类能直接用; - 在基类里加protected的 getter 方法,比如:
然后派生类里用class MySet { std::vector<int> set; public: bool disjoint(const MySet &other) const { /* 你的遍历实现 */ } protected: int getFront() const { return set.front(); } int getBack() const { return set.back(); } };getFront()和getBack()代替直接访问set。
还有个小细节:std::vector没有first()和last()方法,得改成set.front()和set.back()才行。
重载的静态绑定特性得留意
重载是静态绑定的,意思是函数调用是根据你写代码时的变量类型决定的,不是对象实际的类型。举个例子:
MySet* base_ptr = new SortedRange(); SortedRange other; base_ptr->disjoint(other); // 这里会调用基类的disjoint(const MySet&),不是派生类的重载版本
哪怕base_ptr指向的是SortedRange对象,因为base_ptr的类型是MySet*,编译器只会匹配基类的那个版本,用不上你写的高效实现。
如果想不管用基类指针还是派生类指针,都能根据参数实际类型选最优实现,可能得结合虚函数和模板,或者重新设计接口,但这已经超出当前重载的范畴了——当前的重载方式本身没问题,只是要清楚它的适用场景。
总结
总的来说,你这种通过重载基类函数提供派生类特化实现的方式,搭配using避免函数隐藏,完全符合C++的编程规范,根本不是不良实践。只要把基类成员访问权限和vector方法的小错误改了,代码就能正常跑;同时记得重载的静态绑定特性,别踩预期外的坑。
内容的提问来源于stack exchange,提问作者user9478968

