运行时多态指针更改

发布于 2025-01-19 20:49:45 字数 743 浏览 2 评论 0原文

我对多态指针真的很困惑。我有两个从接口派生的类,如下代码所示。

#include <iostream>

using namespace std;

class Base  {

public:
    virtual ~Base() { }
    virtual void addTest() = 0;
};

class B: public Base {

public:
    B(){}
    ~B(){}

    void addTest(){
        cout << "Add test B\n";
    }
};
class C: public Base {

public:
    C(){}
   ~C(){}

    void addTest(){
        cout << "Add test C\n";
    }
private:   
    void deleteTest(){
        
    }
    
};

int main()
{
    Base *base = new B();
    base->addTest();
    base = new C();
    base->addTest();
    return 0;
}

我想根据运行时的条件动态更改指针,以便在不同类型的场景中使用相同的指针。

派生类彼此不同,那么当多态指针对象发生变化时,内存中会发生什么情况呢?

如果这种用法不是好的做法,那么如何在运行时动态更改多态指针对象?

I am really confused about polymorphic pointers. I have 2 classes derived from an interface as shown below code.

#include <iostream>

using namespace std;

class Base  {

public:
    virtual ~Base() { }
    virtual void addTest() = 0;
};

class B: public Base {

public:
    B(){}
    ~B(){}

    void addTest(){
        cout << "Add test B\n";
    }
};
class C: public Base {

public:
    C(){}
   ~C(){}

    void addTest(){
        cout << "Add test C\n";
    }
private:   
    void deleteTest(){
        
    }
    
};

int main()
{
    Base *base = new B();
    base->addTest();
    base = new C();
    base->addTest();
    return 0;
}

I want to change the pointer dynamically according to a condition at run time to use the same pointer with different kinds of scenarios.

Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?

If that usage is not good practice, how can I change the polymorphic pointer object dynamically at the run time?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼眸印温柔 2025-01-26 20:49:46

更改指针指向的内容是完全可以的。 Base* 不是 Base 的实例,它是一个指向 Base 实例的指针(或从它派生的东西 - 在本例中为 BC)。

因此,在您的代码中,base = new B() 将其设置为指向 B 的新实例,然后 base = new C() code> 将其设置为指向 C 的新实例。

派生类彼此不同,那么当多态指针对象发生变化时,内存中会发生什么?

因为 Base* 指向 Base 的一个实例,所以所做的只是更改哪个实例(或派生实例)Base* 指向。实际上,它只是改变了指针的内存地址。

从该 Base* 指针,您仍然可以访问该 Base 类中定义的任何内容——如果该函数定义为,则该类仍然允许对派生类型满足的函数进行多态调用虚拟

从技术上讲,如何将其分派到派生类型的确切机制是语言的实现细节,但通常这是通过称为双分派的过程来完成的,该过程使用“V-Table”。这是与包含虚拟函数的任何类一起存储的附加类型信息(它在概念上只是函数指针的结构,其中函数指针由具体类型满足)。

有关 vtable 的更多信息,请参阅:为什么我们需要虚拟表?


然而,有问题的是这里使用了newnew 分配必须使用delete 清理的内存,以避免内存泄漏。通过执行以下操作:

Base *base = new B();
base->addTest();
base = new C(); // overwriting base without deleting the old instance
base->addTest();

B 对象的析构函数永远不会运行,不会清理任何资源,并且永远不会回收 B 本身的内存。这应该是:

Base *base = new B();
base->addTest();
delete base;
base = new C(); // overwriting base without deleting the old instance
base->addTest();
delete base;

或者,更好的是,应该使用像 std::unique_ptr 这样的智能指针来为您执行此操作。在这种情况下,您不显式使用 newdelete,而是使用 std::make_unique 进行分配,析构函数会自动执行此操作你:

auto base = std::make_unique<B>();
base->addTest();
base = std::make_unique<C>(); // destroy's the old instance before reassigning
base->addTest();

这是编写动态分配的推荐/现代方法

It's perfectly fine to change what a pointer points to. A Base* is not an instance of Base, it is a pointer that points to an instance of a Base (or something derived from it -- in this case B or C).

Thus in your code, base = new B() sets it to point to a new instance of a B, and then base = new C() sets it to point to a new instance of a C.

Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?

Because Base* points to an instance of a Base, all this is doing is changing which instance (or derived instance) Base* points to. In effect, it just changes the memory address of the pointer.

From that Base* pointer, you still have access to anything defined in that Base class -- which still allows polymorphic calls to functions satisfied by derived types if the function is defined as virtual.

The exact mechanism for how this is dispatched to derived types is technically an implementation-detail of the language, but generally this is done through a process called double-dispatch, which uses a "V-Table". This is additional type-information stored alongside any classes that contain virtual functions (it's conceptually just a struct of function pointers, where the function pointers are satisfied by the concrete types).

See: Why do we need a virtual table? for more information on vtables.


What is problematic, however, is the use of new here. new allocates memory that must be cleaned up with delete to avoid a memory leak. By doing the following:

Base *base = new B();
base->addTest();
base = new C(); // overwriting base without deleting the old instance
base->addTest();

The B object's destructor is never run, no resources are cleaned up, and the memory for B itself is never reclaimed. This should be:

Base *base = new B();
base->addTest();
delete base;
base = new C(); // overwriting base without deleting the old instance
base->addTest();
delete base;

Or, better yet, this should be using smart-pointers like std::unique_ptr to do this for you. In which case you don't use new and delete explicitly, you use std::make_unique for allocation, and the destructor automagically does this for you:

auto base = std::make_unique<B>();
base->addTest();
base = std::make_unique<C>(); // destroy's the old instance before reassigning
base->addTest();

This is the recommended/modern way to write dynamic allocations

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文