Reputation: 3934
I have the problem, that I have a pointer to a base class object "Element" in a class "List". In certain situations I need Element to be a more specialized type "Transition". Transition is derived from Element. But when I make a Transition object from the pointer to the Element object the pointer now is decoupled from my matrix class List.
In my research so far, I had read though, that this is the way to create a derived object. But this is not what I had in mind... I want the derived object to be at the same location as the base class pointer (pointer to Element class, "last"). How would I need to do that?
Example code:
#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
}
Upvotes: 2
Views: 85
Reputation: 3934
I realized that I was approaching my issue in an over-complicated manner.
My solution is now this:
#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();
}
Upvotes: 0
Reputation: 172934
Element* last = list.get_last();
last = new Transition;
Now the local variable last
has nothing to do with member variable last
in class List
, so the behaviour on local variable won't influence the member variable last
. You might need a settor method to set it back. Such as:
class List {
public:
void set_last(Element* e) {
last = e;
}
// ...
};
And then in 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: You use a raw pointer in your class List
, you need to pay attention to the management of it. For example, you should delete
it in the destructor, and before set a new pointer to it, delete
the old pointer, and so on. And in general, to adopt RAII idiom by using a smart pointer (such as std::unique_ptr
) is a better solution.
Upvotes: 3
Reputation: 85
First of all, as others are saying.. I think this needs to be re-factored a bit.
But given the question you asked, realize that this:
Element* get_last(){
return last;
}
is returning a pointer to last (the thing you new'd), but you aren't looking to change last, you are looking to change the pointer to last. This could be done like this:
Element** get_last(){
return &last;
}
This would return the pointer to the pointer to element. Then you could then set that pointer to a new object, but realize that if you do that you have just leaked the memory of the element you originally newed. Everything you new must be deleted (even if you go with songyuanyao's comment above.. make sure you delete the old element in the set_last and in your list destructor). So you would end up with:
Element ** last = list.get_last();
delete(*last); // Removes the old entity from memory.
*last = new Transition; // creates completely new entity.
I can think of no circumstance I would write this though.. it really does seem to me like you need some re-factoring.
Upvotes: 0
Reputation: 206627
I want the derived object to be at the same location as the base class pointer (pointer to Element class, "last"). How would I need to do that?
Let me understand what you are trying to do.
You have:
Element* last = list.get_last();
At this point, last
points to a valid object that is either Element
or a sub-type of Element
.
Now you want to create a Transition
object and want that object's address to be the same as the address of the object last
points to?
Short answer: DON'T DO IT
Long answer:
Yes, you can do something like that using the placement new
operator.
However, you must know everything about the memory location before you can use it.
You must know that there is enough memory at that location to hold a Transition
object.
The life of the object that lived there must be terminated by calling its destructor.
No other part of the program tries to access that memory location using the previous object type.
You can't call delete
on the pointer. delete
must be called on the same pointer type that was returned by new
. Otherwise, you will be in undefined behavior territory.
If the memory was allocated using new []
operator, it must be deallocated using the delete []
operator. If the memory was allocated using the plain new
operator, it must be deallocated using the plain delete
operator.
There might be more pitfalls that I don't necessarily recall.
Upvotes: 2