C ++继承父级“知道”子级

时间:2016-06-17 02:21:33

标签: c++ inheritance

你好我有一个全局数组,比方说

array = ["A", "B", "C", "D", "E"]

我想设计一个包含5个子类的父类

Parent, Child1, Child2, Child3, Child4, Child5

Parent类将具有方法名称getID();

我如何设计出现此行为

Child1.getID() is array[0] gives "A"
Child2.getID() is array[1] gives "B"
Child3.getID() is array[2] gives "C"
Child4.getID() is array[3] gives "D"
Child5.getID() is array[4] gives "E"

这可能吗?

原因是我不想为5个孩子保留复制和粘贴getID()。在父类中编写getID()会很好。

3 个答案:

答案 0 :(得分:0)

不,不是那样的。从多个超类中重写虚方法的子类中的虚方法没有指示调用了哪个超类的虚方法。

另一种设计是让每个超类的getid()方法都是非虚拟的,并且是一个调用抽象getMyId()的包装器,向它传递一个参数,即'对每个超类来说都是独一无二的。

父子类实现抽象getMyId()方法,并使用超类传递的参数,指示哪个超类调用抽象方法。

非常简单,直截了当。

答案 1 :(得分:0)

假设我正确理解问题,一种方法是根据类的类型id 查找字符串,例如,

#include <typeinfo>         // Necessary for using `typeid`.
#include <typeindex>        // std::type_index
#include <map>              // Consider using `std::unordered_map` instead.

struct Parent
{
    auto id() const -> char const*;
    virtual ~Parent() {}    // Need something virtual for `typeid`.
};

struct Child1: Parent {};
struct Child2: Parent {};
struct Child3: Parent {};
struct Child4: Parent {};
struct Child5: Parent {};

auto Parent::id() const
    -> char const*
{
    using namespace std;
    static const map<type_index, char const*> ids =
    {
        {typeid( Child1 ), "A"},
        {typeid( Child2 ), "B"},
        {typeid( Child3 ), "C"},
        {typeid( Child4 ), "D"},
        {typeid( Child5 ), "E"}
    };

    return ids.at( typeid(*this) );
}

#include <iostream>
using namespace std;
auto main()
    -> int
{ cout << Child1().id() << Child3().id() << "\n"; }

答案 2 :(得分:0)

我将假设目的是避免在每个子类中重复getID()的身体。但我也认为将数组移动到父类是#34;不理想&#34;。

您可以使用许多选项来避免样板代码。 哪一个最适合您,在很大程度上取决于类的真实用例。

在父

中仅使用一个子类和工厂方法

将公共代码推送到基类并将工厂方法添加到父类(如果合适,您甚至可以合并父类和基类)。

struct ChildBase : public Base {
  explicit ChildBase(const char* name) : name(name) {};
  const char * name; 
  const char * getID() { return name; }
}

struct Base {
   ChildBase getChild1() { return ChildBase("A"); }
   ChildBase getChild2() { return ChildBase("B"); }
}

甚至

struct Base {
   const char* ids = { "A", "B", "C", ...};
   ChildBase getChild(int i) { return ChildBase(ids[i]); }
}

第二种形式很容易概括为在运行时加载配置。

使用基类

将公共代码推送到基类中。

通常情况如下:

struct ChildBase : public Base {
  ChildBase(const char* name) : name(name) {};
  const char * name; 
  const char * getID() { return name; }
}

struct Child1 : public ChildBase {
    Child1() : ChildBase("A") {};
}

struct Child2 : public ChildBase {
    Child2() : ChildBase("B") {};
}

但由于您仍需要自定义构造函数,因此这并不能为您节省很多。您可以使用模板化基类来减少残差

template<const char* ID>
struct ChildBase() { 
   const char* getID() { return ID; }
};

struct Child1 : public ChildBase<"A">();
struct Child2 : public ChildBase<"B">();

是的,宏是邪恶的。但他们可以很容易地解决这样的问题

#define DefineChild(CLASS, ID) \
  struct CLASS : public Base { \
    const char * getID() { \
      return ID; \
    } \
  }

DefineChild(Child1, "A");
DefineChild(Child2, "B");

代码生成

为构建脚本中的每个子类生成基类。 (或者,如果他们像你说的那样空洞,那么就直接把每个孩子课直接分开。)

定义文件 - 这是您配置生成内容的方式。您需要编写一个生成脚本,但这通常非常简单。

Child1 "A"
Child2 "B"
Child3 "C"
...

生成的代码 - 生成脚本的输出

// Generated code - do not edit
struct Child1Base : public Base {
    const char* getID() { return "A"; }
}
...

应用程序代码 - 您可以在此处自定义行为 如果需要,生成的代码。

struct Child1 : public Child1Base {}
struct Child2 : public Child2Base {}
struct Child3 : public Child3Base {}
struct Child4 : public Child4Base {}