派生对象与基本对象位于同一位置

Derived Object at same Location as Base Object

本文关键字:对象 于同一 位置 派生      更新时间:2023-10-16

我有一个问题,我在类"List"中有一个指向基类对象"元素"的指针。在某些情况下,我需要元素成为更专业的"过渡"类型。过渡派生自元素。但是当我创建一个从指针到 Element 对象的过渡对象时,指针现在与我的矩阵类 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
}
Element* last = list.get_last();
last = new Transition;

现在局部变量last与类List中的成员变量last无关,所以局部变量的行为不会影响成员变量last。您可能需要一个 setor 方法来将其设置回来。如:

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

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

让我了解你想做什么。

你有:

Element* last = list.get_last();

此时,last指向一个有效对象,该对象要么是Element,要么是Element的子类型。

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

简短回答:不要这样做

长答案:

是的,您可以使用放置new运算符执行类似操作。

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

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

  2. 必须通过调用其析构函数来终止

  3. 存在在那里的对象的生命。
  4. 程序的其他部分不会尝试使用以前的对象类型访问该内存位置。

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

  6. 如果使用new []运算符分配内存,则必须使用 delete [] 运算符解除分配内存。如果使用纯new运算符分配内存,则必须使用纯delete运算符解除分配内存。

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

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

但鉴于您提出的问题,请注意:

Element*    get_last(){
        return last;
    }

返回指向最后一个的指针(您新的东西(,但您不希望更改最后一个,而是希望将指针更改为最后一个。这可以像这样完成:

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

这将返回指向元素指针的指针。然后,您可以将该指针设置为新对象,但请注意,如果这样做,您只是泄漏了最初更新的元素的内存。所有新元素都必须删除(即使你按照松元瑶上面的评论去做......确保删除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();
}