lo tolmencre
lo tolmencre

Reputation: 3934

Derived Object at same Location as Base Object

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

Answers (4)

lo tolmencre
lo tolmencre

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

songyuanyao
songyuanyao

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

Hashtag
Hashtag

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

R Sahu
R Sahu

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.

  1. You must know that there is enough memory at that location to hold a Transition object.

  2. The life of the object that lived there must be terminated by calling its destructor.

  3. No other part of the program tries to access that memory location using the previous object type.

  4. 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.

  5. 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

Related Questions