nah*_*dev 1 c++ pointers iterator
编辑:TLDR;我是对象切片的受害者,但我对此一无所知。现在原来的问题如下。
我试图了解std::vector<MyClass>当 MyDerived 的实例被push_backed到其中时如何存储对象。另外,迭代器如何知道下一个内存块的开始位置,以便增量++运算符知道如何到达那里。考虑以下代码示例:
#include <iostream>
#include <vector>
using namespace std;
class BaseShape
{
public:
// BaseShape() { cout << "BaseShape() "; }
virtual void draw() const { cout << "BASE?\n"; }
};
class Circle : public BaseShape
{
public:
Circle() { cout << "Circle()"; }
virtual void draw() const override { cout << "Circle!\n"; }
void *somePointer, *ptr2;
};
class Triangle : public BaseShape
{
public:
Triangle() { cout << "Triangle()"; }
virtual void draw() const override { cout << "Triangle!\n"; }
void *somePtr, *ptr2, *ptr3, *ptr4, *ptr5;
};
int main()
{
cout << "vector<BaseShape *> ";
vector<BaseShape *> pShapes{new BaseShape(), new Circle(), new Triangle(), new Circle()};
cout << endl;
for (vector<BaseShape *>::iterator it = pShapes.begin(); it != pShapes.end(); ++it)
{
cout << *it << " ";
(*it)->draw();
}
// vector<BaseShape *> Circle()Triangle()Circle()
// 01162F08 BASE?
// 01162F18 Circle!
// 011661A0 Triangle!
// 01162F30 Circle!
cout << "\nvector<BaseShape> ";
vector<BaseShape> shapes{BaseShape(), Circle(), Triangle(), Circle()};
cout << endl;
for (vector<BaseShape>::iterator it = shapes.begin(); it != shapes.end(); ++it)
{
cout << &(*it) << " ";
(*it).draw();
}
// vector<BaseShape> Circle()Triangle()Circle()
// 01162FD0 BASE?
// 01162FD4 BASE?
// 01162FD8 BASE?
// 01162FDC BASE?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在 中vector::<BaseShape*> pShapes,我知道 pShapes 仅存储指向实际形状地址的指针。然后,很容易知道使用 ++it 增加内存地址多少,因为所有指针都具有相同的内存大小。控制台输出显示*it“三角形”在内存中的跳转情况。
现在,我的疑问是何时vector<BaseShape> shapes使用 。也许我的理解是错误的,但我相信这shapes会直接为 BaseShape 对象存储内存(稍后会详细介绍)。但如果这是正确的,那么当我将一个Circle或一个Triangle对象推入其中时,如何可能将所有对象连续存储在内存中?这听起来不可能,因为Circle和Triangle在内存中具有不同的大小,并且它们的内存必须与 BaseShape 对象的内存相邻(例如 [BaseShape mem][Circle mem])。更重要的是,如何++it准确知道跳转需要多少内存才能获取下一个对象?在控制台输出中,我可以看到++it仅将内存地址增加了 4,这使我得出结论,不知何故只有 BaseShape 部分存储在内存中。[Circle mem] 刚刚被删除了吗?因为我可以看到 Circle 构造函数被调用(如 中所示// vector<BaseShape> Circle()Triangle()Circle())。
我可能期望代码不会编译或警告我存储 Circle 或 Triangleshapes会导致信息丢失,但事实并非如此,并且代码还算有效。“有点”是因为draw()早期绑定到 BaseShape,而不是像虚拟方法那样正确地后期绑定到 Circle 或 Triangle。这表明shapes正在存储连续的 BaseShape 内存块...
我并不是想在这里解决问题,我只是好奇 C++ 是如何工作的,以及我对 std::vector、指针或迭代器的误解在哪里。