Экземпляр подкласса в родительском классе - PullRequest
1 голос
/ 27 ноября 2010

У меня есть два класса в иерархии классов, где родительский класс должен иметь экземпляр класса, производный от него в качестве переменной-члена.В качестве примера:

class B;

class A {
public:
    B* binst;

    A();
};

class B : public A {
};

A::A() {
    binst = new B;
}

Очевидно, что это вызывает бесконечную рекурсию в конструкторах, потому что для создания нового B вам нужно вызвать конструктор A, который создает новый B, который вызывает конструктор A, и поэтому adбесконечности.

Есть ли способ обойти это?Проблема, с которой я сталкиваюсь в этом, состоит в том, что у A должен быть B, но B должен быть получен из A, и нет способа предотвратить это.

Чтобы понять, почему мне нужно это сделать, рассмотрим объектно-ориентированную иерархию для языка сценариев (например, python, ruby, lua и т. Д.):

  1. Все экземплярывсе, что происходит от базового класса, Object.
  2. Объект имеет таблицу поиска метода, которая является экземпляром MethodTable.
  3. MethodTable является производным от Object и должен использоваться языком сценариев для работы с ним.

Ответы [ 8 ]

2 голосов
/ 27 ноября 2010
  • "У объекта есть таблица поиска метода"
  • "MethodTable получен из объекта"

Если оставить в стороне проблемы кодирования, действительно ли эти утверждения имеют смысл вместе даже сконцептуальная точка зрения?Если бы у MethodTable был свой собственный MethodTable, который затем имел бы свой собственный MethodTable ... и т. Д.

Я бы сказал, это звучит так, как будто вам нужно немного реорганизовать свои концепции.Например, возможно, сам Object должен каким-то образом отвечать за предоставление необходимых фрагментов своего члена MethodTable.Таким образом, не требуется, чтобы сам MethodTable был объектом.(Могут быть и другие возможные варианты дизайна. Трудно сказать, не имея более глубоких знаний о реальном проекте.)

0 голосов
/ 21 декабря 2011

Нужно ли ему binst в качестве члена или просто нужно получить к нему доступ?

class B;

class A {
public:
    B& binst(); //throws exception if not derived from B

    A() {}
    virtual ~A() {} //effectively required for the dynamic_cast
    void foo();
};

class B : public A {
public:
    void bar() {};
};

B& A::binst() {return dynamic_cast<B&>(this);} 
void A::foo() {return binst().bar();}
0 голосов
/ 27 ноября 2010
// List(1) or Stream(2) using inheritance
struct B;

struct A { 
  B *inst; 
  A(B *inst_) : inst(inst_) {}
  A()  : inst(0) {}
};

struct B : A {
  B(B *_inst) : A(inst) {}
  // chose option 1 or 2
  B() : A() {}       // option 1: List
  B() : A(0) {}      // same as above
  B() : A(this) {}   // option 2: Stream
};

auto B3 = new B(new B( new B));
// This is either a length 3 list (1)
// or a stream (2) implemented by self ref 3rd element
0 голосов
/ 27 ноября 2010

Я не знаю цели ваших занятий, но вот предложение:

class A
{
public:
    virtual void func DoIt () = 0;
    ...
};

class B : public virtual A
{
public:
};

class C : public virtual A ,B
{
    void func DoIt () { /* statements */ }
};

теперь есть только 1 экземпляр класса А.

0 голосов
/ 27 ноября 2010

Объект может иметь закрытый член MethodTableImpl и публичный метод получения, который возвращает MethodTable. MethodTable содержит MethodTableImpl и является производным от Object.

0 голосов
/ 27 ноября 2010

Вы можете создать конструктор для класса A, который принимает указатель на объект для класса B и назначать этот указатель вместо выделения нового B:

A::A(B* b) : binst (b) {}

И в конструкции класса B вы передаете 'this' в конструктор A:

B::B() : A(this) {} 

Компилятор, вероятно, будет жаловаться на это, но вы можете попробовать. (Хотя это некрасиво.)

Обратите внимание, что вы НЕ можете использовать указатель binst для доступа к объекту B в конструкторе A, потому что он еще не полностью создан.

0 голосов
/ 27 ноября 2010

Было бы полезно понять, что именно вы пытаетесь достичь с помощью этой конструкции.

Как вы уже заметили, это фактически похоже на то, как конструктор A создает экземпляр A, и это неизбежный путь к переполнению стека.

Более общим решением было бы предоставление set_subclass метода для указателя на экземпляр A, который затем мог бы заполняться любым подклассом A, а не только B.

class A {
public:
    A();
    virtual ~A();

    set_subclass(A* sub) { subclass = sub; }
private:
    A* subclass;
};
0 голосов
/ 27 ноября 2010

Редактировать: Как правило, внутренние типы компилятора / реализации не являются производными от зависимых от языка типов.Если вы посмотрите на внутреннюю часть Java, их реализация наследования не будет производной от Object.Объект - это языковая конструкция, это часть интерфейса вашего языка.Таблица методов является частью реализации.Таблица методов не должна управляться языком, она должна управляться реализацией.

Более того, принудительное наследование от Object - глупая вещь, и это происходит потому, что вы не рассматривали языкдизайн и как пользователи собирались написать общий код правильно.Это особенно верно для динамически типизированных языков, таких как Lua или Python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...