2010-11-26 5 views
1

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

class B; 

class A { 
public: 
    B* binst; 

    A(); 
}; 

class B : public A { 
}; 

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

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

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

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

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

Я полагаю, что все Методы Таблицы имеют поиск одной единственной MethodTable, которая имеет поиск к себе, поэтому нет рекурсии. В этом примере нет конструктора `new B`. Нам нужен ваш фактический случай, чтобы выяснить, что делать с «новым B». – Dialecticus 2010-11-26 23:33:53

ответ

0

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

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

0

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

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

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

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

    set_subclass(A* sub) { subclass = sub; } 
private: 
    A* subclass; 
}; 
2
  • «Объект имеет метод таблицы поиска»
  • „MethodTable является производным от объекта“

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

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

+0

хорошо на самом деле, может. Когда-то я развивался в Clipper со сторонней библиотекой для создания пользовательских классов. Там класс класса, который был суперклассом любого другого класса, был реализован как объект. Поскольку у каждого объекта всегда есть класс, к которому он принадлежит, была указанная выше рекурсия. – 2010-11-27 01:38:39

0

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

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

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

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

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

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

+0

выше, я имел в виду, что вы не можете использовать объект B (только указатель) в конструкторе A. – 2010-11-27 00:20:48

0

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

0

Я не знаю цель ваших классов, но здесь это предложение:

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

class B : public virtual A 
{ 
public: 
}; 

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

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

0
// 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

Вы сами это думали, или вы сначала прочитали мой ответ? – 2010-11-27 01:50:07

0

ли это на самом деле нужен 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();} 
Смежные вопросы