【问题标题】:C++ Design (behavior in base class, private member supplied in derived class)C++ 设计(基类中的行为,派生类中提供的私有成员)
【发布时间】:2011-10-11 18:15:38
【问题描述】:

我有 6 个类都执行相同的操作。我想将常见的行为移到一个常见的 [base] 类中。

需要对 6 个单独的对象执行操作。这六个对象位于派生类中。直观地说,私有成员对象将通过基类中的子类(派生类)访问。

我正在寻找的 C++ 模式是什么?

class Base
{
  // Common behavior, operate on m_object
  ...
  void Foo()
  {
    m_object.Bar();
  }
};

class Derived1 : public Base
{
  // No methods, use Base methods

  private:
  MyObject1 m_object;
}

class Derived2 : public Base
{
  // No methods, use Base methods

  private:
  MyObject2 m_object;
}

让我陷入这种情况的是MyObject1MyObject2 等提供Bar(),但不共享一个公共基类。我真的无法修复派生,因为对象来自外部库。

【问题讨论】:

  • 您可以使用 ParentClass::method(args) 在子类中调用 C++ 层次结构,如果这是您所要求的,但可能有更简单的方法来做您想做的事情,就像 Vlad 说的那样,模板。
  • 您到底想达到什么目的?一些代码可以帮助我们帮助您。
  • Java 中的 super 将您带到父类,而不是派生类。基类中的super 会让你一事无成。
  • @Luchian Grigore:我扩展了问题陈述,但我认为这是一个失败的原因。

标签: c++ inheritance composition


【解决方案1】:

如果在派生类中引入它们,则基类不能直接访问它们。基类如何知道所有派生类都有特定的成员?

你可以像这样使用虚拟保护方法:

class my_base
{
protected:
    virtual int get_whatever();
    virtual double get_whatever2();
private:
    void process()
    {
       int y = get_whatever();
       double x = get_whatever2();
       //yay, profit?
    }
}

class my_derived_1 : my_base
{
protected:
    virtual int get_whatever()
    {
        return _my_integer;
    }

    virtual double get_whatever2()
    {
       return _my_double;
    }
}

另一种可能性(如果您想从派生类调用基方法)是简单地将参数提供给基方法。

class my_base
{
protected:
    void handle_whatever(int & arg);
};

class my_derived : my_base
{
    void do()
    {
      my_base::handle_whatever(member);
    }

    int member;
};

【讨论】:

  • “基类如何知道所有派生类都有一个特定的成员”——这就是我要问的;)
  • @noloader:答案是,“它不能。”正如 Max 向您展示的那样,您需要使用虚拟访问器方法。
  • @noloader:Max 提出的是基类使用派生类中的东西的一种(最简单的)方法。基类不能看到它的子成员,除非你使用模板,这方式比 Max 提出的要复杂。
  • @noloader:但是任何假设的“超级”概念也不能回答这个问题——恰恰相反!那你在想什么?
  • @Kerrek SB:我的错。我编辑了问题以记下我的交叉线。
【解决方案2】:

C++ 做和不做。它有非常强大的多重继承支持,所以没有super关键字。为什么?假设您的基类被另外两个类继承,甚至是虚拟继承层次结构的一部分。在这种情况下,您无法真正说出super 应该是什么意思。另一方面,有虚方法,你总是可以将它们放在基类中并在派生类中实现(这就是像 Java 这样的语言所做的,只是它们不支持多类继承)。如果你不想使用多态,你可以使用这样的东西:

#include <cstdio>

template <typename T>
struct Base
{
    void foo ()
    {
        std::printf ("Base::foo\n");
        static_cast<T *> (this)->bar ();
    }
};

struct Derived : Base<Derived>
{
    void bar ()
    {
        std::printf ("Derived::bar\n");
    }
};

int
main ()
{
    Derived d;
    d.foo ();
}

这是一个非常简单的示例 - 您可以使用访问控制、好友、编译时断言等扩展上述示例,但您明白了。

【讨论】:

  • 这个问题是现在派生类不是从同一个基类继承的。但是,它似乎对 OP 并不重要。
【解决方案3】:

你考虑过不使用继承吗?

class FooBar
{
   MyObject m_object;
public:
   FooBar(MyObject m): m_object(m) {}
   //operate on different m_objects all you want
};

【讨论】:

  • 这可能会使事情变得非常复杂,但 MyObject 来自另一个库,并且不可复制。更复杂的是,它必须经历一个初始化/更新/最终生命周期(它是一个加密密码)。常见的行为是 init/update/final。
  • “你有没有考虑过不使用继承” - 是的,但我不想[重新]实现每个派生类中的所有内容。外部库对象不共享一个公共基类让我很生气(但它们确实提供了我正在使用的相同方法)。我想我将不得不接受它。
  • 那么template &lt;class LibraryObject&gt; class FooBar { LibraryObject libo; ... };(或者甚至只是一个调用生命周期函数的函数模板)呢?
【解决方案4】:

从一个公共基类派生六个独立的对象怎么样?然后您可以在该基类中声明虚拟方法来创建您的接口,然后在派生对象类中实现它们。

【讨论】:

  • 这基本上就是我现在所拥有的。这是一个巨大的复制和粘贴工作。每当一个班级发生变化时,我必须将这些变化传播到其他五个班级。
  • @noloader:如果你有,就没有理由将任何东西传播到派生类。
【解决方案5】:

也许您只需要一个模板而不是超类和 6 个派生类?

似乎您需要访问的不是父字段,而是子字段。您应该通过引入抽象方法来做到这一点:

class ParentClass
{
  public:
    void f();
  protected:
    virtual int getSomething() = 0;
};

ParentClass::f()
{
    cout << getSomething() << endl;
}

class DerivedClass : public ParentClass
{
  protected:
    virtual int getSomething();
}

DerivedClass::getSomething() { return 42; }

如果你需要访问parent的方法,只需使用ParentClass::method(...)

class ParentClass
{
  public:
    virtual void f();
};

class DerivedClass : public ParentClass
{
  public:
    virtual void f();
};

void DerivedClass::f()
{
    ParentClass::f();
}

【讨论】:

  • 我想从基类中使用派生类中的对象。
猜你喜欢
  • 2015-12-11
  • 2017-04-14
  • 1970-01-01
  • 2014-11-27
  • 2017-08-07
  • 1970-01-01
  • 2011-01-02
  • 2018-01-05
相关资源
最近更新 更多