在基类中混合使用虚函数和非虚函数是不好的编程实践吗?
Is it bad programming practice to mix virtual and non-virtual functions in a base class?
我有一个基类base,我声明了几个多态子类。基类的一些函数是纯虚函数,而其他函数则由子类直接使用。
(这都是c++)
例如:
class Base
{
protected:
float my_float;
public:
virtual void Function() = 0;
void SetFloat(float value){ my_float = value}
}
class subclass : public Base
{
void Function(){ std::cout<<"Hello, world!"<<std::endl; }
}
class subclass2 : public Base
{
void Function(){ std::cout<<"Hello, mars!"<<std::endl; }
}
因此,正如您所看到的,子类将依赖于设置"my_float"的函数的基类,但对于另一个函数来说将是多态的。
所以我想知道这是否是一个好的实践。如果你有一个抽象基类,你是应该让它完全抽象,还是可以采用这种混合方法?
这是一种常见的做法。事实上,一些著名的设计模式依赖于此,例如模板方法模式。简而言之,这允许您将通过类层次结构描述的行为的某些方面指定为不变的,而让该行为的其他方面根据您在给定点引用的特定实例类型而变化。
是否它是一个好或不取决于你的精确用例:它是有意义的,你在所有的基类中共享浮点成员数据存储的实现?这是一个有点难回答的例子,你张贴作为派生类不依赖于my_float
以任何方式,但有吨的情况下,这是有意义的,是一个很好的方式来分割你的类层次结构的责任。
即使在跨类共享细节实现确实有意义的情况下,您也有几个其他选择,例如使用组合来共享功能。与通过组合共享功能相比,通过基类共享功能通常可以减少冗余,因为它允许您共享实现和接口。为了说明,您的解决方案比使用组合的替代方案具有更少的重复代码:
class DataStorage {
private:
float data_;
public:
DataStorage()
: data_(0.f) {
}
void setFloat(float data) {
data_ = data;
}
};
class NotASubclass1 {
private:
DataStorage data_;
public:
void SetFloat(float value){ data_.setFloat(value); }
...
}
class NotASubclass2 {
private:
DataStorage data_;
public:
void SetFloat(float value){ data_.setFloat(value); }
...
}
能够使某些函数非虚有一定的好处,其中许多是密切相关的:
-
您可以修改它们,知道通过
Base*
/Base&
调用将使用您修改的代码,而不管Base*
指向什么实际派生类型-
例如,您可以收集所有
Base*/&
s的性能测量值,而不管它们的派生 -
非虚拟接口(NVI)方法的目标是"两全其美"——非虚拟函数调用非公共虚拟函数,给你一个单一的地方通过
Base
中的Base*/&
拦截调用,以及可定制性
-
-
对非虚函数的调用可能会更快——如果内联的话,对于像get/set这样的小函数来说,速度可能会快一个数量级
-
您可以确保从
Base
派生的所有对象的不变性,有选择地封装一些私有数据和影响它的函数(在c++ 11中引入的final
关键字允许您在层次结构中进一步这样做) -
在
Base
类中"最终确定"数据/功能有助于理解和推理类行为,并且分解使代码总体上更简洁,但必然以令人失望的灵活性和不可预见的重用为代价调到品味
- 有一个打印语句的函数是一种糟糕的编程实践吗
- C++使用模板元编程生成函数
- 在C++中编程,将 3 个数字发送到一个函数,然后计算这 3 个数字的平均函数
- 如何使用模板元编程在自由函数C++链接两个不相关的类
- 返回不停止函数,递归函数问题?(编程练习,动态规划,Levenshtein 回溯)
- 以编程方式在 C++ 中创建函数
- 创建析构函数是好的编程实践吗?
- 当您希望在Arduino Uno编程中同时执行不同函数时,使用什么代码/语句
- 使用C++元编程提取 C 函数的参数("Practical C++ Metaprogramming" 中的示例)
- 函数模板编程而不是继承
- 可视化 在C++编程中编写一个函数星号
- C++函数式编程.实施 f(a)(b)(c)
- C :对输入验证函数进行编程的性能影响可以对其进行编程,而每次都可以将其编程
- 是否有任何函数可用于在 c++ 编程中传输流程,以替代 while 或 do while 循环
- 在使用英特尔内部函数对 SIMD 代码进行编程时,如何强制使用 vmovapd 而不是 vmovupd?
- CPP 元编程:包含元组函数
- 模板元编程:检查稍后定义的函数是否存在
- 是c++模板元编程的一种函数编程形式
- 为什么Erlang和其他函数编程语言不是原生的c/c++
- 形成递归函数C++编程