带有或不带有虚类的子类vs性能vs便利

问题描述

| 众所周知,STL类不在任何地方使用虚拟方法(并且STL也不在任何地方使用继承,并且这两个事实是相互关联的),并且STL并不是唯一的。 假设地球上还存在其他性能怪胎[存在],这些性能怪胎会为每个类要求自己“我是否需要为此类X使用虚方法?”和“此类X是否可以不任何虚拟机,就像STL类一样,都能获得更好的性能?\“ 与“ virtuals”基类相比,缺少任何虚拟方法包括dtor)都会使多态和子类化更加困难。显然,“非虚拟”类不太适合作为基类。 问题:是否有技术(用于c ++)允许程序员一次性创建两个相同类X的版本,一个“非虚拟”版本Xnv(用于性能)和一个“虚拟”版本Xv,用于子类化?如果不需要,请说明原因。
Post-note
人们回答 \“如果需要子类化,请使用虚拟。如果不需要,请不要使用虚拟\”。 这个建议有问题。几个问题。 1)需求经历了随着时间变化的变化。那时不需要从类X继承子类,但是现在需要,反之亦然。 2)写基类的人与写派生类的人不同。从问题中可以清楚地看出这一点。人们有不同的思维方式,不同的判断和不同的需求。再说一遍 3)因此,不同的程序员回答“是否从类X继承是否有意义?”之类的问题,将给出不同的答案。这是主观的,没有明确的答案。 4)与所问的问题相矛盾。 因此,我们希望满足频谱的两端(这在工程中经常发生),这是问题背后的动力。 动机太复杂,无法在问题中简明扼要地表达出来。我认为人们可以(1)假设问题已经被精确地提出来就存在动机,或者可以(2)因为人们已经处于c ++设计的权衡平衡情况下而计算动机。 没有人知道这个动机-令我惊讶的是-甚至现在。这对我来说是一个教训。 我接受了提到CRTP的答案,因为它是一种有趣的模式。     

解决方法

           问题:是否有技术(用于c ++)允许程序员一次性创建两个相同类X的版本,一个“非虚拟”版本Xnv(用于性能)和一个“虚拟”版本Xv,用于子类化? 当您可以吃蛋糕时也为什么要这样做呢? 使用CRTP,您具有编译时多态性,并且子类具有覆盖行为的能力,而虚拟函数没有任何开销。 或者,您可以使用\“ traits \”类来注入行为。     ,        我想你可以...
struct Base
{
    virtual ~Base();
    virtual void foo();
};

struct Dummy {};

template <bool is_virtual>
struct SelectBase
{
    typedef Base type;
};

template <>
struct SelectBase<false>
{
    typedef Dummy type;
};

template <bool is_virtual>
struct MyClass : SelectBase<is_virtual>::type
{
    ~MyClass();
    void foo();
};

int main()
{
    Base* xv = new MyClass<true>(); // virtual version
    MyClass<false>* xnv = new MyClass<false>(); // non-virtual version
    xv->foo(); // virtual call
    xnv->foo(); // non-virtual call
}
我真的没有想到这样做的充分理由。     ,        与其先担心性能,不如说一个更好的问题是“从此类继承是否有点道理?”如果答案是否定的,那么为什么要虚拟化任何东西?毕竟,从本质上讲,最终课程具有一些存储和性能优势。 (尽管C ++不支持Java类
final
类的概念,但是没有虚拟方法的类几乎可以被称为'final \'。) 但是,我通常走相反的路线:我倾向于将析构函数虚拟化,因为其他人可能会看到从类继承的用途。     ,        我认为您对决定是否使方法虚拟化的原因感到困惑。性能不是使您的方法具有虚拟性或非虚拟性的原因之一,事实上,性能的影响往往很小。[1] 是否提供虚拟方法的决定应基于您的要求,尤其是:您是否需要运行时多态性?如果这样做,则这些方法应该是虚拟的,如果不这样做,则它们应该不是。 [1]在具有单继承的设计中,虚拟分派仅采用一个额外的间接,而在多分派中,代价会稍高一些,可能会产生额外的指针偏移和间接。这样的代价将比该方法执行的任何操作都要小得多。     ,另一件事是您以后可以简单地编写它。
template<typename T> class something {
    virtual const T& operator*() = 0;
    virtual something<T>& operator++() = 0;  // This should be only prefix
    // etc
};

template<typename Derived,typename T> class something_better : public something<T> {
    typename Derived::const_iterator i;
public:
    something_better(const Derived& d) {
        i = d.begin();
    }
    const T& operator*() {
        return *i;
    }
    something<T>& operator++() {
        ++i;
        return *this;
    }
    something<T>& operator--() {
        --i;
        return *this;
    }
};
等等,运行时多态迭代。那很简单。当然,只要迭代器和容器继续有效即可。 如果要进行非const迭代等操作,则需要等到C ++ 0x正确处理rvalues。或问“四”人,他们似乎已经以某种方式解决了问题。     ,        我对此假设表示怀疑:   就像STL类一样,为了获得更好的性能? 我不同意缺乏虚拟性是出于性能方面的考虑。   与“ virtuals”基类相比,缺少任何虚拟方法(包括dtor)都会使多态和子类化更加困难。 非常真实这就是我在容器类中没有虚函数的原因。它是故意设计成不能被子类化的。使用容器类时,最好使用成员资格而不是继承。   问题:是否有技术(用于c ++)允许程序员一次性创建两个相同类X的版本,一个“非虚拟”版本Xnv(用于性能)和一个“虚拟”版本Xv,用于子类化?如果不需要,请说明原因。 你为什么想这么做。 如果为性能而设计,那么您的界面通常会从基本的OO界面更改。在暴露内部信息时,您往往会变得松懈一些(因为通常是为了更紧密地耦合类而交易速度)。 为了获得更高的性能,该算法通常会更多地了解内部原理,以便可以使用此信息对其工作原理进行假设。因此,您可以以将存储耦合到使用该存储的算法为代价来提高性能。