最近我回答了another question asking for 。My suggestion是
Q: How does a pointer point to an object?
A: The pointer stores the address of that object.但是user R..不同意我向Q建议的A-他说正确的答案是“它是特定的实现”。虽然当前的实现将数字地址存储为指针,但没有理由要做更详细的事情。
当然,我不能不同意,除了为了不同意而存储一个地址之外,还有其他的实现。我非常感兴趣的是,还有哪些其他真正使用过的实现。
除了在整数类型变量中存储地址外,在C++中其他实际使用的指针实现是什么?铸造(特别是dynamic_cast)是如何实现的?
发布于 2010-10-15 07:00:36
在概念层面上,我同意你的观点--我将对象的地址定义为“在内存中定位对象所需的信息”。然而,地址的样子可能会有很大的差异。
现在的指针值通常表示为一个简单的线性地址.但是,有些体系结构的地址格式并不那么简单,或者根据类型的不同而有所不同。例如,在x86上以实模式编程(例如在DOS下),有时必须将地址存储为段:偏移对。
有关更多示例,请参见http://c-faq.com/null/machexamp.html。我发现对Symbolics机器的引用很有趣。
发布于 2010-10-15 07:47:24
我会传唤Boost.Interprocess作为证人。
在Boost.Interprocess中,进程间指针是从映射内存区域开始的偏移量。这允许从另一个进程获取指针,映射内存区域(哪个指针地址可能与传递指针的进程中的指针地址不同),并且仍然到达同一个对象。
因此,进程间指针并不表示为地址,而是可以解析为一个地址。
谢谢收看:)
发布于 2010-10-15 09:01:07
如果我们熟悉使用指针算法访问数组元素,那么很容易理解对象是如何放置在内存中的以及dynamic_cast是如何工作的。考虑以下简单的类:
struct point
{
point (int x, int y) : x_ (x), y_ (y) { }
int x_;
int y_;
};
point* p = new point(10, 20); 假设p被分配给内存位置0x01。它的成员变量存储在各自不同的位置,比如x_存储在0x04,y_存储在0x07。将对象p可视化为一个指针数组比较容易。p (在我们的例子中(0x1) )指向数组的开头:
0x01
+-------+-------+
| | |
+---+---+----+--+
| |
| |
0x04 0x07
+-----+ +-----+
| 10 | | 20 |
+-----+ +-----+因此,访问字段的代码本质上将变成使用指针算法访问数组元素:
p->x_; // => **p
p->y_; // => *(*(p + 1))如果语言支持某种类型的自动内存管理,比如GC,那么可以在场景后面的对象数组中添加额外的字段。假设有一个C++实现,它借助引用计数收集垃圾。然后编译器可能会添加一个额外的字段(rc)来跟踪这个计数。然后,上面的数组表示形式变成:
0x01
+-------+-------+-------+
| | | |
+--+----+---+---+----+--+
| | |
| | |
0x02 0x04 0x07
+--+---+ +-----+ +-----+
| rc | | 10 | | 20 |
+------+ +-----+ +-----+第一个单元格指向引用计数的地址。编译器将发出适当的代码来访问应该对外部世界可见的p部分:
p->x_; // => *(*(p + 1))
p->y_; // => *(*(p + 2))现在很容易理解dynamic_cast是如何工作的。编译器通过向底层表示添加额外的隐藏指针来处理多态类。这个指针包含另一个名为vtable的‘数组’开头的地址,后者又包含这个类中虚拟函数实现的地址。但是vtable的第一个条目是特殊的。它不是指向一个函数地址,而是指向一个名为type_info的类的对象。此对象包含对象的运行时类型信息和指向其基类的type_info的指针。请考虑以下示例:
class Frame
{
public:
virtual void render (Screen* s) = 0;
// ....
};
class Window : public Frame
{
public:
virtual void render (Screen* s)
{
// ...
}
// ....
private:
int x_;
int y_;
int w_;
int h_;
};Window的一个对象将具有以下内存布局:
window object (w)
+---------+
| &vtable +------------------+
| | |
+----+----+ |
+---------+ vtable | Window type_info Frame type_info
| &x_ | +------------+-----+ +--------------+ +----------------+
+---------+ | &type_info +------+ +----+ |
+---------+ | | | | | |
| &y_ | +------------------+ +--------------+ +----------------+
+---------+ +------------------+
+---------+ | &Window::render()|
+---------+ +------------------+
+---------+
| &h_ |
+---------+现在,考虑一下当我们尝试将Window*转换为Frame*时会发生什么
Frame* f = dynamic_cast<Frame*> (w);dynamic_cast将遵循w的vtable中的type_info链接,确认Frame在其基类列表中,并将w分配给f。如果在列表中找不到Frame,则f设置为0,表示转换失败。vtable提供了一种表示类的type_info的经济方法。这就是为什么dynamic_cast只适用于具有virtual函数的类的原因之一。从逻辑的角度来看,将dynamic_cast限制为多态类型也是有意义的。也就是说,如果一个对象没有虚拟函数,那么如果不知道它的确切类型,就不可能安全地操作它。
目标类型的dynamic_cast不一定是多态的。这允许我们将具体类型封装为多态类型:
// no virtual functions
class A
{
};
class B
{
public:
virtual void f() = 0;
};
class C : public A, public B
{
virtual void f() { }
};
C* c = new C;
A* a = dynamic_cast<A*>(c); // OKhttps://stackoverflow.com/questions/3939876
复制相似问题