当我声明一个基类时,我应该将其中的所有函数声明为虚拟,还是应该有一组虚函数和一组非虚函数,我相信这些函数不会被继承?< / p>
答案 0 :(得分:8)
如果派生类将以不同的方式实现该函数,则函数只需要是虚拟的。
例如:
class Base {
public:
void setI (int i) // No need for it to be virtual
{
m_i = i;
}
virtual ~Base () {} // Almost always a good idea
virtual bool isDerived1 () // Is overridden - so make it virtual
{
return false;
}
private:
int m_i;
};
class Derived1 : public Base {
public:
virtual ~Derived () {}
virtual bool isDerived1 () // Is overridden - so make it virtual
{
return true;
}
};
因此,除非您提前知道您打算覆盖它或直到您发现需要该行为,否则我会错误地认为没有任何虚拟内容。唯一的例外是析构函数,其几乎总是希望它在基类中是虚拟的。
答案 1 :(得分:4)
您应该只创建您想要的功能并设计为覆盖虚拟。在维护和性能方面,使虚拟方法不是免费的(维护是更大的问题恕我直言)。
一旦方法是虚拟的,就很难推断使用这种方法的任何代码。因为不是考虑一个方法调用会做什么,而是必须考虑N方法调用在该场景中会做什么。 N表示覆盖该方法的子类的数量。
此规则的一个例外是析构函数。它们应该在任何旨在派生的类中是虚拟的。这是保证在释放期间调用正确的析构函数的唯一方法。
答案 2 :(得分:4)
非虚拟接口习惯用法(C ++ Coding Standards第39项)说基类应该具有非虚拟接口方法,允许基类保证不变量,以及非公共虚方法用于定制基类行为通过派生类。非虚接口方法调用虚方法来提供可覆盖的行为。
答案 3 :(得分:2)
我倾向于只制作我想要覆盖虚拟的东西。如果我对我想要覆盖的内容的初步假设结果是错误的,我会回去更改基类。
哦,显然,如果你正在处理将继承的东西,你的构造函数会变得虚拟。
答案 4 :(得分:1)
如果您正在创建基类(您确定某人派生了该类),那么您可以执行以下操作:
答案 5 :(得分:1)
当基类型的指针调用虚函数时,编译器不知道将运行哪一段实际代码。因此,需要在运行时根据基类指针指向哪个对象来评估要运行的实际代码片段。因此,如果函数不是在继承的类中重写,则避免使用虚函数。
TLDR版本: “你应该拥有一组虚拟函数和一组非虚函数,你肯定不会继承这些函数。”因为虚函数会导致运行时性能下降。
答案 6 :(得分:0)
接口函数通常应该是虚拟的。提供固定功能的功能不应该。
答案 7 :(得分:0)
为什么要声明某些虚拟内容,直到你真的重写它为止?我相信这不是一个肯定与否的问题。遵循事实:它是否覆盖某处?没有?然后它一定不是虚拟的。