【问题标题】:Inheritance: Evaluating In Derived Class's Scope?继承:在派生类的范围内进行评估?
【发布时间】:2013-05-15 14:45:44
【问题描述】:

在任何主流语言中是否存在派生类从基类继承代码并在派生类范围内评估该代码的设计模式?例如(使用伪 C++ 语法):

class Base {
    // (How) can this be modified to be evaluated 
    // in the derived class's scope so that it
    // prints the size of the derived class?
    void printSize() {
        cout << sizeof(*this) << endl;
    }
};

class Derived : public Base {
    void* dummy;
};

int main() {
    Base base;
    Derived derived;
    base.printSize();  
    derived.printSize();  // Should be > base.printSize().
    return 0;
}

我意识到这可以通过宏来完成,但这需要在派生类的范围内显式实例化宏。

编辑:澄清一下,这篇文章的重点是我不想在每个派生类中手动重新实现printSize() 或类似的东西。我正在寻找一种聪明的模式来制作编译器/解释器(我很想知道是否有任何语言有解决方案,即使我在我的示例中使用了 C++)为我做这个。

编辑#2:我想这在动态语言中很容易。我对静态类型语言的解决方案更感兴趣,主要是 C++、Java 和 D。

EDIT #3:该模式应该适用于运行时类型,而不是编译时类型。所以,D的模板这个参数不是解决办法。

【问题讨论】:

  • 评估是什么意思?如果你给它看起来像正常的继承给我
  • printSize() 将始终打印基类的大小,因为它在 Base 范围内编译一次。如果在 Derived 的实例上调用它,我希望它打印派生类的大小。
  • 这仅适用于 c++ 语言。使用 java,当然还有正确的 java 语法,这将自动被认为是虚拟的,并会打印派生类的大小
  • 注意printSize()返回void,所以你可能不想cout &lt;&lt;它;你可能打算自己打电话给printSize()
  • @Adam:对。已编辑。

标签: java c++ oop design-patterns d


【解决方案1】:

如果“主流”包括主流脚本语言,例如 Perl 或 Python,那么可以。 Perl 方法通常在派生最多的范围内“评估”,因为 Perl“对象”通常是一个哈希映射,并且来自继承树所有级别的所有变量都在同一个“范围”内(即,进入相同的哈希图)。 Python 类也会发生类似的情况,尽管 (IIRC) Python 有一种方法可以创建一个符号,该符号将被破坏,以便根据编写代码的类而有所不同。当然,这些语言都没有“sizeof” " 概念本身,因此您的特定示例不会特别相关。

在 C++ 中,像您的示例那样根据调用它的类型来决定成员函数的当前类的概念(据我所知)并不真正有效。但是,您可能能够接近您使用模板所描述的内容。例如,像这样:

template<typename T>
void printSize( T &t ) {
    cout << sizeof(t) << endl;
}
int main() {
    Base base;
    Derived derived;
    printSize(base);
    printSize(derived);
}

(旁注:在 C++ 中,由于您的 Base 是空的,实际上并不能保证 sizeof(Base) > sizeof(Derived) --- 可以使用空基优化,这样一个普通的 Base 是(也许) 指针的大小,但 DerivedBase 部分实际上是空的。大多数平台可能会为此类空类分配 1 个字节,而指针通常比这大,但未指定。)

【讨论】:

    【解决方案2】:

    D 前来救援。 Template mixins 正是用于在目标上下文中评估的工具,您不需要任何特殊的类型层次结构(当然,如果需要,您仍然可以添加一个):

    http://dpaste.1azy.net/eec411e8

    mixin template SizePrinter()
    {
        static void printSize()
        {
            import std.stdio;
            writeln(__traits(classInstanceSize, typeof(this)));
        }
    }
    
    class Tested1
    {
        int[64] dummy;
        mixin SizePrinter;
    }
    
    class Tested2
    {
        int[16] dummy;
        mixin SizePrinter;
    }
    
    void main()
    {
        Tested1.printSize();
        Tested2.printSize();
    }
    

    应用程序输出:

    272
    80
    

    【讨论】:

    • 我知道 D 中的模板混合。它是比 C++ 提供的更好的解决方案,但它仍然需要在派生类中明确地完成一些事情,即使它是一个也可能很烦人-班轮。
    • 啊,dsimcha,对不起,我没有注意到这是D社区的人问的。您对 RTTI 方法满意吗?
    • RTTI 可以解决需要类大小的特定情况,但这不是通用解决方案。
    • @dsimcha 好吧,您绝对需要某种运行时反射,因为基类不可能控制或知道谁从它继承。如果您只关心有限的模块集,您可以迭代其中的所有类,找到具有目标 Base 的类并使用 typeid 来识别当前的类。如果您希望它跨动态加载的库边界工作,则需要实现某种形式的运行时类型注册,并且无法避免。
    • 但我仍然质疑是否明智地花这么多精力避免显式使用 mixin 语句(并显式使用继承)来处理 D 类型系统旨在实际防止的事情,
    【解决方案3】:

    在 C++ 中,我认为您会更接近于 Curiously Recurring Template Pattern (CRTP),但它有严重的局限性:

    template<typename T>
    class Base {
        void printSize() {
            std::cout << sizeof(T) << std::endl;
        }
        void doSomething() {
            T::member_variable = 3;
            T::doSomethingElse();
        }
    };
    
    class Derived : public Base<Derived> {
    public:
        int member_variable;
        void doSomethingElse() { ... }
    };
    

    您也可以使用虚拟方法,但它们需要您在每个派生类中重新实现该方法,所以我想这不是您想要的。

    要真正实现您的想法,您可能需要一种动态语言(例如 Python)。但不能保证,这是一个不寻常的“功能请求”,我不太了解动态语言......

    【讨论】:

      【解决方案4】:

      在 D 中有一个更好的解决方案,它使用Template This Parameter

      代码:http://dpaste.1azy.net/78810a79

      import std.stdio;
      
      class Base {
        int[64] dummy1;
        final static size_t getSize(this T)() {
          return __traits(classInstanceSize, T);
        }
      }
      
      class Derived : Base {
        int[16] dummy2;
      }
      
      void main() {
        writeln(Base.getSize());    // prints: 272
        writeln(Derived.getSize()); // prints: 336
      }
      

      编辑:操作,这仅适用于静态类型。不是您问题的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-07
        • 2021-09-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多