我知道对于任何具有虚函数的类或者从具有虚函数的类派生的类,编译器会做两件事.首先,它为该类创建一个虚拟表,然后,它将虚拟指针(vptr)放在该对象的基础部分中.在运行时,此vptr被分配并在对象实例化时开始指向正确的vtable.
我的问题是,在实例化过程中,这个vptr的确切位置是什么?这个vptr的赋值是否发生在构造函数之前/之后的对象的构造函数中?
我将不死子句称为 C++ 规则,即在对象销毁后,如果在同一地址创建新对象,有时可以将其视为与旧对象相同的对象。该规则始终存在于 C++ 中,但对附加条件进行了一些更改。
这个问题让我阅读了最新的不死条款。Lifetime [basic.life]/8中修改后的条件是:
(8.1) 新对象的存储正好覆盖原对象所占用的存储位置,并且
嗯,呵呵。位于不同地址的对象不会是同一个对象。
(8.2) 新对象与原始对象的类型相同(忽略顶级 cv 限定符),以及
再说一遍,呵呵。
(8.4) 原始对象和新对象都不是潜在重叠的子对象 ([intro.object])。
它不能是基类、经典类(或具有使其地址不唯一的特殊声明的成员)。再说一遍,呵呵。
(8.3) 原始对象既不是 const 限定的完整对象,也不是此类对象的子对象,并且
现在这很有趣。被替换的对象不能是:
另一方面,被复活的对象可以是:
所以在我看来,所有这些对象x都可以复活:
常量成员子对象
struct CI {
const int x;
};
CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2
Run Code Online (Sandbox Code Playgroud)
const 成员的子对象:
struct T {
int x;
};
struct CT …Run Code Online (Sandbox Code Playgroud) 以下是否定义明确?
#include <iostream>
#include <string.h>
using namespace std;
struct Const {
const int i;
Const (int i) : i(i) {}
int get0() { return 0; } // best accessor ever!
};
int main() {
Const *q,*p = new Const(1);
new (p) Const(2);
memcpy (&q, &p, sizeof p);
cout << q->i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意,在构造第二个之后Const,p在语义上(故意?)指向新对象,并且第一个已经消失,因此它可以"用作void*".但是第二个对象是在完全相同的地址构造的,因此位模式p表示新对象的地址.
评论
new (p) Const(2)擦除存储在的旧对象p,因此指针不再有效,除非作为指向storage(void*)的指针.
我想恢复p作为一个的价值Const*.
评论2
在任何一个p->~Const()或 …
对于这个问题,不涉及多态性,即不涉及虚方法,不涉及虚基类。以防万一,我的案子不涉及其中任何一个。
假设我有一个类Derived,它有一个明确的可访问父类型Base,没有多态性(没有虚拟方法,没有虚拟基类),但可能涉及间接和/或多继承。进一步假设我有一个有效的指针Derived *derived
(指向类型Derived或其子类的对象)。
在这种情况下,我相信static_cast<Base*>(derived)是有效的(产生有效的可用指针)。Base当和之间的祖先链Derived涉及多重继承时,这static_cast可能意味着指针调整以在实例Base内定位实例Derived。为此,编译器需要知道继承链,在本例中他就是这样做的。但是,如果插入了中间转换void *,则编译器将隐藏该继承链信息。对于哪个继承链来说,这样的静态转换仍然有效?我期望以下之一:
static_castfrom void 指针是未定义的行为,除非该指针确实指向确切的类型。Base始终位于Derived- 但标准怎么说?Base在所有中间多重继承链的第一个父类中可以找到什么?Base也许和的开始Derived仍然匹配?static_castto void 指针始终可以调整到第一个父级的开头,而static_castfrom void 指针则撤消该调整。但对于多重继承,“第一个父母”不一定是所有父母的父母。编辑:原始的单词选择令人困惑.术语"象征性"比原始术语("神秘")要好得多.
在关于我以前的C++问题的讨论中,我被告知指针是
这并没有健全的权利!如果没有任何符号,并且指针是其表示,那么我可以执行以下操作.我可以吗?
#include <stdio.h>
#include <string.h>
int main() {
int a[1] = { 0 }, *pa1 = &a[0] + 1, b = 1, *pb = &b;
if (memcmp (&pa1, &pb, sizeof pa1) == 0) {
printf ("pa1 == pb\n");
*pa1 = 2;
}
else {
printf ("pa1 != pb\n");
pa1 = &a[0]; // ensure well defined behaviour in printf
}
printf ("b = %d *pa1 = %d\n", …Run Code Online (Sandbox Code Playgroud) 这是我在"我不理解C和C++中的指针"集合中的一个新问题.
如果我将具有相同值的两个指针的位混合(指向相同的存储器地址),那恰好具有完全相同的位表示,当一个是可解除引用且一个是结束时,标准说应该发生什么?
#include <stdio.h>
#include <string.h>
#include <assert.h>
// required: a == b
// returns a copy of both a and b into dest
// (half of the bytes of either pointers)
int *copy2to1 (int *a, int *b) {
// check input:
// not only the pointers must be equal
assert (a == b);
// also the representation must match exactly
int *dest;
size_t s = sizeof(dest);
assert(memcmp(&a, &b, s) == 0);
// copy a and b into dest:
// …Run Code Online (Sandbox Code Playgroud) c++ ×6
pointers ×2
arrays ×1
c ×1
const ×1
constants ×1
constructor ×1
inheritance ×1
lifetime ×1
memcpy ×1
static-cast ×1
upcasting ×1
vptr ×1
vtable ×1