Производный объект в том же месте, что и базовый объект
У меня есть проблема, что у меня есть указатель на объект базового класса "элемент" в классе "список". В определенных ситуациях мне нужен элемент более специализированного типа "переход". Переход происходит от элемента. Но когда я делаю объект перехода от указателя к объекту элемента, указатель теперь отделен от моего списка классов матрицы.
Однако до сих пор в своих исследованиях я читал, что это способ создания производного объекта. Но это не то, что я имел в виду... Я хочу производный объект должен находиться в том же месте, что и указатель базового класса (указатель на класс элемента, "последний"). Как бы я должен это делать?Пример кода:
#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
}
4 ответа:
Теперь локальная переменная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]
Кстати: вы используете необработанный указатель в своем классеList
, вам нужно обратить внимание на управление им. Например, вы должныdelete
его в деструкторе, а перед этим установить новый указатель на него,delete
старый указатель и так далее. И вообще, принять идиому RAII с помощью интеллектуального указателя (например,std::unique_ptr
) - лучшее решение.
Позвольте мне понять, что вы пытаетесь сделать.Я хочу, чтобы производный объект находился в том же месте, что и указатель базового класса (указатель на класс элемента, "последний"). Как бы я должен это делать?
У вас есть:
Element* last = list.get_last();
В этой точке
Теперь вы хотите создать объектlast
указывает на допустимый объект, который является либоElement
, либо подтипомElement
.Transition
и хотите, чтобы адрес этого объекта совпадал с адресом точек объектаlast
. куда?Короткий ответ: Не делай этого
Длинный ответ:
Да, вы можете сделать что-то подобное, используя оператор placement
Тем не менее, вы должны знать все о местоположении памяти, прежде чем сможете его использовать.new
.Возможно, есть и другие подводные камни, о которых я не обязательно вспоминаю.
Вы должны знать, что в этом месте достаточно памяти для хранения объекта
Transition
.Жизнь объекта, который жил там, должна быть прекращена путем вызова его деструктор.
Никакая другая часть программы не пытается получить доступ к этой области памяти, используя предыдущий тип объекта.
Вы не можете вызвать
delete
по указателю.delete
должен быть вызван на тот же тип указателя, который был возвращенnew
. В противном случае вы окажетесь на неопределенной территории поведения.Если память была выделена с помощью оператора
new []
, она должна быть освобождена с помощью оператораdelete []
. Если память была выделена с помощью равнины Операторnew
, он должен быть освобожден с помощью простого оператораdelete
.
Прежде всего, как говорят другие.. Я думаю, что это нужно немного пересмотреть.
Но учитывая вопрос, который вы задали, поймите, что это:Element* get_last(){ return last; }
Возвращает указатель на last (вещь, которую вы обновили), но вы не хотите изменить last, вы хотите изменить указатель на last. Это можно было бы сделать так:
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.
Я понял, что подходил к своей проблеме слишком сложным образом.
Мое решение теперь таково:
#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(); }