c++中的多态类指针
C++ polymorphic class pointer in vector
假设我有以下代码,简而言之,有:
- 指向
PointerClass
的BaseClass
- 继承
BaseClass
的ChildClass
-
HolderClass
具有ChildClass
s的std::vector
和BaseClass*
s的std::vector
:
整个代码如下:
#include <stdlib.h>
#include <time.h>
#include <vector>
class PointerClass {
public:
int num;
double num2;
PointerClass() {
srand(time(NULL));
num = rand() % 100;
num2 = rand() % 100 / 2.0;
}
};
class BaseClass {
public:
PointerClass *pointerClass;
};
class ChildClass: public BaseClass {
public:
ChildClass() {
pointerClass = new PointerClass();
}
};
class HolderClass {
public:
std::vector<BaseClass*> basePointerVec;
std::vector<ChildClass> childVec;
HolderClass() {
}
void addParentClass() {
ChildClass childClass = ChildClass();
childVec.push_back(childClass);
basePointerVec.push_back(&childClass);
}
};
int main(int argc, const char * argv[]) {
HolderClass holderClass = HolderClass();
for (int count = 0; count < 20; count++) {
holderClass.addParentClass();
}
for (int count = 0; count < holderClass.basePointerVec.size(); count++) {
delete holderClass.basePointerVec[count]->pointerClass;
}
return 0;
}
我的问题是,在HolderClass
的addParentClass()
方法中将ChildClass
的指针添加到std::vector<BaseClass*> basePointerVec
和实际的ChildClass
中添加到std::vector<ChildClass> childVec
后,basePointerVec
和childVec
中的数据完全不同。
此外,当我尝试从childVec
中释放PointerClass
时,一切都工作正常。但是当我试图从basePointerVec
中释放它们时,我得到一个错误,告诉我我正在试图释放一个我没有分配内存的指针。
果然,当我使用断点检查所有内容时,我发现了一些奇怪的行为。似乎每次我在addParentClass()
中调用ChildClass childClass = ChildClass();
, basePointerVec
中的每个指针都被更改为指向新创建的ChildClass
的BaseClass
。
我在实际程序中这样做的目的是利用多态性,并从BaseClass
继承多个类。
所以我的问题是,为什么每个指针在向量被改变为指向新创建的类,我怎么能修复它?
注:很抱歉这个问题太长了,我已经尽可能的短了
childVec.push_back(childClass);
类vector的push_back方法复制对象。所以在这个例子中,添加的对象和childClass不一样。
你不能从basePointerVec中删除指针,因为它们不是用new分配的,而是在本地分配的,并且它们在addParentClass的末尾被删除。所以,addParent的代码是错误的,因为你在向量中推送的指针在方法结束后不再有效,并可能导致分段错误(在最好的情况下)。以下是一个改进建议:
void addParentClass() {
ChildClass* childClass = new ChildClass();
childVec.push_back(*childClass);
basePointerVec.push_back(childClass);
}
内存现在是动态分配的,你应该确保用delete释放这些指针。
编辑:void addParentClass() {
childVec.push_back(ChildClass());
basePointerVec.push_back(&childVec.back());
}
如果你使用c++ 11:
void addParentClass() {
childVec.emplace_back();
basePointerVec.push_back(&childVec.back());
}
其他答案已经解决了代码中的特定问题。以下是关于你的程序的两个要点,它们将帮助你在未来避免各种各样的问题:
-
当你定义一个类,特别是一个可以被子类化的类时,除非你有特殊的原因不能这样做,否则总是让医生
public virtual
。 -
始终按照RAII原则在类中存储资源:
-
除非有很好的理由,否则永远不应该使用裸成员指针。使用
shared_ptr
成员代替。 -
除非有很好的理由,否则你永远不应该有一个裸指针的
vector
。再次使用共享指针的向量
-
使用这个,希望,你不需要在你的头脑中跟踪什么东西被破坏了,当一些东西被复制到任何东西,等等。这将使混淆堆对象和堆栈对象变得更加困难。
看这里:
void addParentClass() {
ChildClass childClass = ChildClass();
childVec.push_back(childClass);
basePointerVec.push_back(&childClass);
}
对象没有在堆上分配。它们是值,在basePointerVec
中,您将它们的地址(在addParentClass()
返回之后无论如何都没有意义)。不要试图删除那些,那会使你的程序崩溃。当childVec
超出范围时,它们将被自动删除。
当addParentClass
返回时,childClass
对象被销毁。因此,您放入basePointerVec
中的指向该对象的指针不能再使用了。
您正在创建一个局部变量,一旦addParentClass
超出范围就会被销毁。也可以看看这个问题的答案,它解释了当你不使用new
时会发生什么。因此,BaseClass
指针的向量指向一个被销毁的对象,而childVec
指针的对象向量在使用push_back
时正在创建新的副本,从这个页面:
新元素初始化为value的副本。
这就是为什么两个向量指向不同的对象。您可以为类创建析构函数,并在析构函数和构造函数中添加调试打印,以查看对象何时被创建/销毁,这将使您更好地了解以何种顺序发生了什么。
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- Doees the 'this' 指针参与虚函数的多态行为
- 如何在基类指针向量的元素上应用重载的多态函数
- 具有智能指针的多态性
- 当目标指针不是基类的类型时,为什么允许dynamic_cast为多态类生成 null 指针?
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- 无法初始化已知大小的矢量指针,该大小不会因多态性而更改
- 如何调用指针类型的方法(禁用多态性)?
- 当依赖关系和依赖关系都是多态时,在哪个继承级别存储依赖关系指针?
- 创建基类指针的向量并将派生类对象传递给它(多态性)
- 对于多态类型T,如何在没有类型T实例的情况下获得指向T的虚拟表的指针
- 如何避免指针超出范围(多态性)的C++分段错误
- C++ 被此代码与多态性、指针和对象切片混淆
- 在同时处理基类的多个指针时如何处理多态性?
- 如果基类指针无法访问派生类成员函数,那么多态性有什么方便的呢?
- 为什么在将多态行为与指向接口的指针一起使用时没有调用析构函数?
- 集合中的智能指针多态性
- c++智能指针多态
- 智能指针与哑指针:多态行为奇特