2015-04-08 4 views
2

У меня проблема, что у меня есть указатель на объект базового класса «Элемент» в классе «Список». В определенных ситуациях мне нужно, чтобы Element был более специализированным типом «Переход». Переход происходит от элемента. Но когда я делаю объект Transition из указателя на объект Element, указатель теперь отделен от моего списка классов матриц.Производный объект в том же месте, что и базовый объект

В моих исследованиях до сих пор я читал, что это способ создания производного объекта. Но это не то, что я имел в виду ... Я хочу, чтобы производный объект находился в том же месте, что и указатель базового класса (указатель на класс Element, «последний»). Как мне это сделать?

Пример кода:

#include <iostream> 


class Element{ 

    public: 

     Element(){ 
      member = 0; 
     } 

     virtual void set_member(int i){} 

     void print_member(){ 
     std::cout << member << std::endl; 
    } 

    protected: 
     int member; 

}; 


class Transition: public Element{ 

    public: 
     void set_member(int i){ 
      member = i; 
     } 

}; 


class List{ 

    public: 

    List(){ 
     last = new Element; 
    } 

    Element* get_last(){ 
      return last; 
     } 

    void print(){ 
     last->print_member(); 
    } 

    private: 
     Element* last; 

}; 

int main(){ 

    List list; 
    Element* last = list.get_last(); 
    last = new Transition; // creates completely new entity. 
          // I wanted to make a derived object 
          // from Element at the same location 
          // as the Elememt object though 
    last->set_member(1); 
    last->print_member(); // returns newly assigned value 
    list.print(); // returns default value of Element type 
        // but I wanted itto return newly assigned value 

} 
+0

Пожалуйста, обратите внимание, что вы код, как написано, по меньшей мере две утечки памяти. Возможно, стоит описать то, что вы на самом деле пытаетесь сделать, таким образом, вы можете найти ответ, который решает вашу реальную проблему (т. Е. Способ структурирования решения). – Lionel

+0

Ну, что я на самом деле хочу сделать, чтобы получить доступ к последнему элементу списка с помощью последнего указателя, который является атрибутом моего класса списка. Затем я хочу изменить атрибут последнего элемента списка. –

ответ

3
Element* last = list.get_last(); 
last = new Transition; 

Теперь локальная переменная last не имеет ничего общего с переменной-члена last в классе List, поэтому поведение на локальной переменной не будет влиять на переменную-член last. Возможно, вам понадобится метод настройки, чтобы вернуть его. Такие, как:

class List { 
public: 
    void set_last(Element* e) { 
     last = e; 
    } 

    // ... 
}; 

, а затем в main:

int main() { 
    List list; 
    Element* last = new Transition; // creates completely new entity. 
    last->set_member(1); 
    list.set_last(last);   // set it back to List 
    list.print(); 
} 

[EDIT]
BTW: Вы можете использовать сырой указатель в классе List, вам нужно обратить внимание на управление Это. Например, вы должны delete в деструкторе и перед установкой нового указателя на него, delete старый указатель и так далее. И вообще, для принятия RAII-идиомы с помощью умного указателя (например, std::unique_ptr) - лучшее решение.

+0

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

2

Я хочу, чтобы производный объект находился в том же месте, что и указатель базового класса (указатель на класс элемента, «последний»). Как мне это нужно сделать?

Позвольте мне понять, что вы пытаетесь сделать.

У вас есть:

Element* last = list.get_last(); 

На данный момент, last указывает на действительный объект, который либо Element или подтип Element.

Теперь вы хотите создать объект Transition и хотите, чтобы адрес этого объекта был таким же, как адрес объекта last указывает на?

Короткий ответ: НЕ ДЕЛАЙТЕ IT

Длинный ответ:

Да, вы можете сделать что-то подобное с помощью placement new operator.

Однако, прежде чем вы сможете его использовать, вы должны знать все о памяти.

  1. Вы должны знать, что имеется достаточно памяти в этом месте провести Transition объект.

  2. Жизнь объекта, который там жила, должна быть прекращена путем вызова ее деструктора.

  3. Ни одна другая часть программы не пытается получить доступ к этой ячейке памяти с использованием предыдущего типа объекта.

  4. Вы не можете позвонить по телефону delete по указателю. delete должен быть вызван одним и тем же типом указателя, который был возвращен new. В противном случае вы будете находиться на неопределенной территории поведения.

  5. Если память была выделена с использованием оператора new [], ее необходимо освободить, используя оператор delete []. Если память была распределена с использованием простого оператора new, его необходимо освободить, используя простой оператор delete.

Возможно, здесь может быть больше подводных камней, которые я не обязательно вспоминаю.

+0

Спасибо, тогда этот подход явно выходит за рамки моего нынешнего уровня понимания. –

0

Прежде всего, как говорят другие. Я думаю, что это нужно немного переустановить.

Но данный вопрос, который вы просили, понимаешь, что это:

Element* get_last(){ 
     return last; 
    } 

возвращает указатель на последний (вещь вы new'd), но вы не хотите последнего изменения, вы смотрите для изменения указателя на последний. Это можно сделать следующим образом:

Element** get_last(){ 
     return &last; 
    } 

Это вернет указатель на указатель на элемент. Затем вы можете установить этот указатель на новый объект, но поймите, что если вы это сделаете, вы просто пропустили память элемента, который вы изначально вывели. Все, что вы новичок необходимо удалить (даже если вы пойдете с комментарием songyuanyao выше .. убедитесь, что вы удаляете старый элемент в set_last и в своем деструкторе списка). Таким образом, вы бы в конечном итоге с:

Element ** last = list.get_last(); 
delete(*last); // Removes the old entity from memory. 
*last = new Transition; // creates completely new entity. 

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

0

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

Мое решение теперь это:

#include <iostream> 


class Element{ 

    public: 

     Element(){ 
      member = 0; 
      successor = 0; 
     } 

     virtual void set_member(int i){} 

     virtual void set_successor(int successor){} 

     void print(){ 
     std::cout << member << std::endl; 
     std::cout << successor << std::endl; 
    } 

    protected: 
     int member; 
     int successor; 

}; 


class Transition: public Element{ 

    public: 
     void set_member(int i){ 
      member = i; 
     } 

     void set_successor(int i){ 
      successor = i; 
     } 

}; 


class List{ 

    public: 

    List(){ 
     last = new Transition; 
    } 

    Element* get_last(){ 
      return last; 
    } 

    void set_last(Element* new_last){ 
     last = new_last; 
    } 

    void print(){ 
     last->print(); 
    } 

    private: 
     Element* last; 

}; 

int main(){ 

    List list; 
    (list.get_last())->set_member(6); 
    (list.get_last())->set_successor(8); 
    list.print(); 

} 
Смежные вопросы