代码之家  ›  专栏  ›  技术社区  ›  John Bartholomew

类和它的基类之间有什么可察觉的区别?

  •  3
  • John Bartholomew  · 技术社区  · 15 年前

    给定以下模板:

    template <typename T>
    class wrapper : public T {};
    

    类型的对象之间在接口或行为上有什么明显的区别 Foo 和类型的对象 wrapper<Foo> ?

    我已经知道一个:

    • 包装器<Foo> 只有空构造函数、复制构造函数和赋值运算符(并且只有那些操作在 ). 这种差异可以通过使用一组模板化的构造函数来缓解 wrapper<T> 将值传递给T构造函数。

    但我不确定还有什么其他可察觉的差异,或者是否有隐藏它们的方法。


    (编辑)具体示例

    我经常编写一些代码,这些代码的值可以调整,以调整系统的精确性能和操作。我想有一个简单(低代码开销)的方式,通过配置文件或用户界面公开这些值。我目前正在写一个库,允许我这样做。预期设计允许如下使用:

    class ComplexDataProcessor {
        hotvar<int> epochs;
        hotvar<double> learning_rate;
    public:
        ComplexDataProcessor():
            epochs("Epochs", 50),
            learning_rate("LearningRate", 0.01)
            {}
    
        void process_some_data(const Data& data) {
            int n = *epochs;
            double alpha = *learning_rate;
            for (int i = 0; i < n; ++i) {
                // learn some things from the data, with learning rate alpha
            }
        }
    };
    
    void two_learners(const DataSource& source) {
        hotobject<ComplexDataProcessor> a("FastLearner");
        hotobject<ComplexDataProcessor> b("SlowLearner");
        while (source.has_data()) {
            a.process_some_data(source.row());
            b.process_some_data(source.row());
            source.next_row();
        }
    }
    

    FastLearner.Epochs
    FastLearner.LearningRate
    SlowLearner.Epochs
    SlowLearner.LearningRate
    

    这是由代码组成的(碰巧我的用例甚至不是机器学习),但它展示了设计的几个重要方面。可调整的值都被命名,并且可以组织成一个层次结构。值可以由几个方法分组,但在上面的示例中,我只展示了一个方法:将对象包装到 hotobject<T> 班级。在实践中 包装器的工作相当简单——它必须将对象/组名推送到线程本地上下文堆栈上,然后允许 T hotvar<T> 值被构造并检查上下文堆栈以查看它们应该在哪个组中),然后弹出上下文堆栈。

    具体做法如下:

    struct hotobject_stack_helper {
        hotobject_stack_helper(const char* name) {
            // push onto the thread-local context stack
        }
    };
    
    template <typename T>
    struct hotobject : private hotobject_stack_helper, public T {
        hotobject(const char* name):
            hotobject_stack_helper(name) {
            // pop from the context stack
        }
    };
    

    1. hotobject_stack_helper 构造(将名称推送到上下文堆栈上)
    2. T型 是构造的——包括构造 的成员(hotvars)
    3. 尸体 构造函数运行,弹出上下文堆栈。

    所以,我有工作代码来做这个。然而,还有一个问题,那就是:使用这个结构,我可能会给自己带来什么问题。这个问题很大程度上归结为我要问的一个问题:hotobject的行为和T本身有什么不同?

    4 回复  |  直到 15 年前
        1
  •  0
  •   Potatoswatter    15 年前

    对对象的引用可转换(给定访问权限)为对基类子对象的引用。有语法糖来调用隐式转换,允许您将对象视为基的实例,但这才是真正的情况。不多不少。

    所以,这种差异一点也不难发现。它们(几乎)完全不同。“is-a”关系和“has-a”关系的区别在于指定成员名称。

    至于隐藏基类,我认为你无意中回答了你自己的问题。通过指定 private (或省略) public class ),并且这些转换不会发生在类本身之外,并且没有其他类能够判断出基是否存在。

        2
  •  3
  •   GManNickG    15 年前

    奇怪的问题,因为你应该问一些关于你的具体用法的问题(“我想做什么,这对我有什么帮助或伤害”),但我想一般来说:

    wrapper<T> 不是一个 T ,所以:

    • . (正如你所说。)
    • 它不能像一个 T型 .
    • 它失去了通往私人空间的通道 T型 有权访问。

    我相信还有更多,但前两个涵盖了很多。

        3
  •  2
  •   Daniel Earwicker    15 年前

    class Base {};
    class Derived : Base {};
    

    现在你可以说:

    Base *basePtr = new Derived;
    

    wrapper<Base> *basePtr = new wrapper<Derived>();
    

        4
  •  0
  •   Benoît photo_tom    15 年前

    如果继承的类有自己的成员变量(或至少一个),那么

    sizeof(InheritedClass) > sizeof(BaseClass)