子类

时间:2017-03-29 16:01:05

标签: c++ inheritance static field

请考虑以下代码:

#include <stdio.h>
#include <iostream>

/// Header-file
class Base {
public:
  virtual void do_something() const =0;

  int GetAttrib () const {return constattribute_;};

  static const int constattribute_;
};

typedef Base* Derived_Ptr; //<< adress derived classes by their base-class ptr; so no templates for Base

class DerivedA : public Base {
//   static const int constattribute_; //<< change this static attribute for all DerivedA class instances and their derivatives

  void do_something() const {};
};

class DerivedB : public Base {
//   static const int constattribute_; //<< change this static attribute for all DerivedB class instances and their derivatives

  void do_something() const {};
};

/// CC-file
using namespace std;

const int Base::constattribute_(0);
const int DerivedA::constattribute_(1); //<<error: no such variable 'constattribute' in class DerivedA
const int DerivedB::constattribute_(2); //<<error: no such variable 'constattribute' in class DerivedB


int main(void) {
  Derived_Ptr derivedA = new DerivedA();
  Derived_Ptr derivedB = new DerivedB();

  cout << derivedA->GetAttrib() << derivedB->GetAttrib() <<endl;
  return 0;
};

我打算使用一些抽象接口(Base)来定义一个变量,该变量应该存在于所有派生类中,并且是可检索的。所有类型的子类都应该被强制/能够重新定义这个变量的特定值,最好在类声明期间(这些值在类声明之后就已知)。

我想实现代码,而不是改变main() - 程序,以便输出为'12'而不是现在(在代码中取消注释当前行)'00'(这样做会影响基类中的字段) )。

我试图调查此事,解决方案有不同的路径,但其中许多与我的直觉相反: 1.有些人遵循CRTP模式,但如果我想通过main中的base-ptr来解决我的子类,那么这是不可能的。 2.其他解决方案需要为每个派生实例虚拟化'GetAttrib()'函数,这很麻烦,并且修改属性的操作在函数定义中被屏蔽。 3.第三种可能性是删除静态模式并将'constattribute_'字段作为常规成员,然而这迫使我将其作为参数拖动到所有构造函数中。

我很确定必须有一些更聪明的方法来做到这一点。任何提示都表示赞赏。

3 个答案:

答案 0 :(得分:0)

您请求的内容需要虚拟调度某处,因为您在运行时之前不知道要处理的对象的类型。虚拟调度的目的是准确解决您所面临的问题。

最简单的解决方案是你给出的数字2:make GetAttrib()虚拟,并在你引入阴影constattribute_的每个派生类上实现它。

答案 1 :(得分:0)

基类中的静态变量是单个实例,因此它将在派生类中反映出来。

您可以在派生类中使用您想要的特定不同值创建相同的静态成员变量。现在将Base类中的静态变量的getter成员函数作为virtual,并在派生类中重载它,返回的是静态实例值。

我已更新您的代码以便使用它,请检查..

#include <iostream>

using namespace std;

class Base {
public:
  static const int constattribute_;
  virtual void do_something() const =0;
  virtual int GetAttrib () const {return constattribute_;};
};

typedef Base* Derived_Ptr; //<< adress derived classes by their base-class ptr; so no templates for Base

class DerivedA : public Base {
  static const int constattribute_; //<< change this static attribute for all DerivedA class instances and their derivatives

  void do_something() const {};
  int GetAttrib () const {return constattribute_;};
};

class DerivedB : public Base {
  static const int constattribute_; //<< change this static attribute for all DerivedB class instances and their derivatives

  void do_something() const {};
  int GetAttrib () const {return constattribute_;};
};

const int Base::constattribute_(0);
const int DerivedA::constattribute_(1); //<<error: no such variable 'constattribute' in class DerivedA
const int DerivedB::constattribute_(2); //<<error: no such variable 'constattribute' in class DerivedB


int main(void) {
  Derived_Ptr derivedA = new DerivedA();
  Derived_Ptr derivedB = new DerivedB();

  cout << derivedA->GetAttrib() << derivedB->GetAttrib() <<endl;

  return 0;
};

你应该得到所需的输出。

注意:请记住派生类中的所有成员变量和func都是私有的。

答案 2 :(得分:0)

使用CRTP可能会得到您想要的,假设您不必通过Base *访问GetAttr()并且可以在Base本身中不使用constattribute_。只需遵循以下规则即可通过进入另一个间接层来解决每个编程问题,我在下面做了:

class Base {
  public:
    virtual void do_something() const = 0;

    virtual ~Base()     // should define it as you are using Base*
    {
    }
};

typedef Base* Derived_Ptr;

template<class T>
class BaseConstAttr : public Base
{
  public:
    int GetAttrib () const
    {
      return(constattribute_);
    };

    static const int constattribute_;
};

class DerivedA : public BaseConstAttr<DerivedA>
{
  public:
    void do_something() const
    {
    };
};

class DerivedB : public BaseConstAttr<DerivedB>
{
  public:
    void do_something() const
    {
    };
};

template<> const int BaseConstAttr<DerivedA>::constattribute_(1);
template<> const int BaseConstAttr<DerivedB>::constattribute_(2);

如果你需要从继承树的顶部到底部获取GettAttr,你可以稍微修改上面的代码,但这会花费你让GetAttr虚拟(但仍然只有一个实现):

class Base {
  public:
    virtual void do_something() const = 0;
    virtual int GetAttrib () const = 0;

    virtual ~Base()     // should define it as you are using Base*
    {
    }
};

typedef Base* Derived_Ptr;

template<class T>
class BaseConstAttr : public Base
{
  public:
    int GetAttrib () const
    {
      return(constattribute_);
    };

    static const int constattribute_;
};

class DerivedA : public BaseConstAttr<DerivedA>
{
  public:
    void do_something() const
    {
    };
};

class DerivedB : public BaseConstAttr<DerivedB>
{
  public:
    void do_something() const
    {
    };
};

template<> const int BaseConstAttr<DerivedA>::constattribute_(1);
template<> const int BaseConstAttr<DerivedB>::constattribute_(2);

请注意,我不知道它在深度继承树中的表现有多好(或者不好)(即从DerivedA和/或DerivedB继承时)。在这种情况下,我可能会从Base下面的继承树中删除BaseConstAttr,并尝试在大多数派生类和它的前任之间注入它或使用多重继承。