多态指针在 运行 时间发生变化
Polymorphic pointer change at run time
我对多态指针真的很困惑。我有 2 类 从接口派生,如下代码所示。
#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;
}
我想在 运行 时根据条件动态更改指针,以便在不同类型的场景中使用相同的指针。
派生的类各不相同,那么当多态指针对象发生变化时,内存中会发生什么?
如果这种用法不是好的做法,我如何才能在 运行 时动态更改多态指针对象?
更改指针指向的内容完全没问题。 Base*
不是 Base
的实例,它是一个指针 指向 Base
的实例(或派生自它的东西 - - 在这种情况下 B
或 C
).
因此在您的代码中,base = new B()
将其设置为指向 B
的新实例,然后 base = new C()
将其设置为指向 [= 的新实例17=].
Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?
因为Base*
指向一个Base
的实例,所有这一切都在改变哪个实例(或派生实例)Base*
指着。实际上,它只是改变了指针的内存地址。
从那个 Base*
指针,你仍然可以访问那个 Base
class 中定义的任何东西——如果函数是定义为 virtual
.
如何将其分派到派生类型的确切机制在技术上是语言的 implementation-detail,但通常这是通过称为 double-dispatch 的过程完成的,该过程使用“V-Table”。这是额外的 type-information 与包含 virtual
函数的任何 class 一起存储(它在概念上只是一个 struct
函数指针,其中函数指针由具体类型满足) .
有关 vtable 的更多信息,请参阅:Why do we need a virtual table?。
然而,有问题的是这里使用了 new
。 new
分配必须使用 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
一样使用 smart-pointers 来为您完成此操作。在这种情况下,您不显式使用 new
和 delete
,而是使用 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();
这是recommended/modern编写动态分配的方式
我对多态指针真的很困惑。我有 2 类 从接口派生,如下代码所示。
#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;
}
我想在 运行 时根据条件动态更改指针,以便在不同类型的场景中使用相同的指针。
派生的类各不相同,那么当多态指针对象发生变化时,内存中会发生什么?
如果这种用法不是好的做法,我如何才能在 运行 时动态更改多态指针对象?
更改指针指向的内容完全没问题。 Base*
不是 Base
的实例,它是一个指针 指向 Base
的实例(或派生自它的东西 - - 在这种情况下 B
或 C
).
因此在您的代码中,base = new B()
将其设置为指向 B
的新实例,然后 base = new C()
将其设置为指向 [= 的新实例17=].
Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?
因为Base*
指向一个Base
的实例,所有这一切都在改变哪个实例(或派生实例)Base*
指着。实际上,它只是改变了指针的内存地址。
从那个 Base*
指针,你仍然可以访问那个 Base
class 中定义的任何东西——如果函数是定义为 virtual
.
如何将其分派到派生类型的确切机制在技术上是语言的 implementation-detail,但通常这是通过称为 double-dispatch 的过程完成的,该过程使用“V-Table”。这是额外的 type-information 与包含 virtual
函数的任何 class 一起存储(它在概念上只是一个 struct
函数指针,其中函数指针由具体类型满足) .
有关 vtable 的更多信息,请参阅:Why do we need a virtual table?。
然而,有问题的是这里使用了 new
。 new
分配必须使用 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
一样使用 smart-pointers 来为您完成此操作。在这种情况下,您不显式使用 new
和 delete
,而是使用 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();
这是recommended/modern编写动态分配的方式