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

Derived Object at same Location as Base Object

我有一个问题,我在 class "List" 中有一个指向基础 class 对象 "Element" 的指针。在某些情况下,我需要 Element 成为更专业的类型 "Transition"。 Transition 派生自 Element。但是,当我从指向 Element 对象的指针创建一个 Transition 对象时,该指针现在与我的矩阵 class List.

解耦了

到目前为止,在我的研究中,我读到过,这是创建派生对象的方法。 但这不是我想要的……我希望派生对象与基础 class 指针(指向元素 class、"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

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

现在局部变量last与classList中的成员变量last没有任何关系,所以局部变量的行为不会影响成员变量 last。您可能需要一个 settor 方法来将其设置回来。如:

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();
}

[编辑]
BTW:你在你的classList中使用了裸指针,你需要注意它的管理。例如,你应该在析构函数中delete它,并在为它设置一个新指针之前,delete旧指针,等等。而且一般来说,使用智能指针(如std::unique_ptr)来采用RAII惯用语是更好的解决方案。

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?

让我明白你想做什么。

你有:

Element* last = list.get_last();

此时,last 指向一个有效对象,它是 ElementElement 的子类型。

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

简短回答:不要这样做

长答案:

是的,您可以使用 placement new operator.

做类似的事情

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

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

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

  3. 程序的其他部分没有尝试使用先前的对象类型访问该内存位置。

  4. 您不能在指针上调用 deletedelete 必须在 new 返回的相同指针类型上调用。否则,您将处于未定义的行为领域。

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

可能还有更多我不一定记得的陷阱。

首先,正如其他人所说..我认为这需要重构一下。

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

Element*    get_last(){
        return last;
    }

是 return 指向 last(你新建的东西)的指针,但你不想改变 last,你想改变指向 last 的指针。可以这样做:

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

这将return指向元素指针的指针。然后你可以将该指针设置为一个新对象,但要意识到如果你这样做,你只是泄漏了你最初新建的元素的内存。你新 的所有东西都必须 被删除(即使你按照上面 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();

}