与基础对象位于同一位置的派生对象

时间:2015-04-08 02:29:05

标签: c++ pointers derived

我遇到了问题,我在“List”类中​​有一个指向基类对象“Element”的指针。在某些情况下,我需要Element作为更专业的类型“Transition”。转换源自Element。但是当我从指向Element对象的指针创建一个Transition对象时,指针现在与我的矩阵类List分离。

到目前为止,在我的研究中,我读过,这是创建派生对象的方法。 但这不是我想到的......我希望派生对象与基类指针(指向Element类的指针,“last”)位于同一位置。 我怎么需要这样做?

示例代码:

#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 个答案:

答案 0 :(得分:3)

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

现在局部变量last与类last中的成员变量List无关,因此局部变量上的行为不会影响成员变量{{1 }}。您可能需要settor方法来重新设置它。如:

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(); } 中使用原始指针,你需要注意它的管理。例如,您应该在析构函数中List,并在设置新指针之前,delete旧指针,依此类推。一般而言,通过使用智能指针(例如delete)来采用RAII习惯用法是更好的解决方案。

答案 1 :(得分:2)

  

我希望派生对象与基类指针位于同一位置(指向Element类的指针,“last”)。我怎么需要这样做?

让我了解你的目标。

你有:

Element* last = list.get_last();

此时,last指向有效对象Element或子类型Element

现在您要创建一个Transition对象,并希望该对象的地址与对象last指向的地址相同?

简短回答:不要做

答案很长:

是的,您可以使用placement new operator执行类似的操作。

但是,您必须先了解有关内存位置的所有信息,然后才能使用它。

  1. 您必须知道该位置有足够的内存来容纳Transition个对象。

  2. 生活在那里的对象的生命必须通过调用它的析构函数来终止。

  3. 程序的其他任何部分都不会尝试使用以前的对象类型访问该内存位置。

  4. 您无法在指针上调用delete。必须在delete返回的同一指针类型上调用new。否则,您将处于未定义的行为区域。

  5. 如果使用new []运算符分配内存,则必须使用delete []运算符取消分配。如果内存是使用普通new运算符分配的,则必须使用普通delete运算符取消分配。

  6. 我可能不会想起更多的陷阱。

答案 2 :(得分:0)

首先,正如其他人所说的那样......我认为这需要重新考虑一下。

但是考虑到你提出的问题,请意识到这一点:

Element*    get_last(){
        return 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.

我可以想到没有任何情况我会写这个......但在我看来,你需要一些重新分解。

答案 3 :(得分: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();

}