GCC-3.4.6源代码学习笔记(139)
2011-01-02 12:56
239 查看
5.12.5.2.2.2.1.3.9.
完成派生类的
RECORD_TYPE
–
布局
回到
finish_struct_1
中,下面的
keyed_classes
是一个保存那些在这个编译单元中将可能发布
vtable
的类的
tree_list
。这个链表中的候选者是不含有非内联、非纯虚方法的类。换而言之,是仅含有纯虚方法或(及)内联虚方法的类。对于这样的类,在每个该类定义出现的编译单元中(如,通过
#include
),应该发布其
vtable
;而对于含有其它虚方法的类,每个包含了其虚方法定义的编译单元要发布其
vtable
。
finish_struct_1 (continue)
5033
/* Find the key
method.
*/
5034
if (TYPE_CONTAINS_VPTR_P (t))
5035
{
5036
CLASSTYPE_KEY_METHOD (t) = key_method
(t);
5037
5038
/* If a
polymorphic class has no key method, we may emit the vtable
5039
i
n every translation unit where the class
definition appears.
*/
5040
if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE)
5041
keyed_classes
= tree_cons (NULL_TREE, t, keyed_classes
);
5042
}
5043
5044
/* Layout the class
itself.
*/
5045
layout_class_type
(t, &virtuals);
5046
if (CLASSTYPE_AS_BASE (t) != t)
5047
/* We use the base type for trivial
assignments, and hence it
5048
needs a mode.
*/
5049
compute_record_mode
(CLASSTYPE_AS_BASE (t));
CLASSTYPE_KEY_METHOD
保存了类中第一个非内联及非纯虚方法
,这个域在
vtable
的产生过程中要用到。
4973
static
tree
4974
key_method
(tree type)
in class.c
4975
{
4976
tree method;
4977
4978
if (TYPE_FOR_JAVA (ty
pe)
4979
||
processing_template_decl
4980
||
CLASSTYPE_TEMPLATE_INSTANTIATION (type)
4981
||
CLASSTYPE_INTERFACE_KNOWN (type))
4982
return
NULL_TREE;
4983
4984
for
(method =
TYPE_METHODS (type); method != NULL_TREE;
4985
method = TREE_CHAIN (method))
4986
if (DECL_VINDEX (method) != NULL_TREE
4987
&& ! DECL_DECLARED_INLINE_P
(method)
4988
&& ! DECL_PURE_VIRTUAL_P
(method))
4989
return
method;
4990
4991
return
NULL_TREE;
4992
}
记住在类模板中是不允许出现虚函数的。
如果我们已经确定了是否要在该编译单元中产生
vtable
,
VTT
,
typeinfo
及其他类似的类维护数据,
CLASSTYPE_INTERFACE_KNOWN
是
true
,这样的类即便满足上述条件,也不应该被保存在
keyed_classes
中。
接着我们可以为类布局来决定类型的真正的大小,每个数据成员的偏移量,大小,填充字节,甚至由编译器产生的维护数据。毫无疑问,这是一个相当复杂的过程。
在深入到代码之前,我们首先看一下
GCC
为下面的例子所做的布局:
例
1
:
class
A { virtual
A* f (); };
class
B1 : virtual
public
A { virtual
B1* f (); };
class
B2 : virtual
public
A { virtual
B2* f (); };
class
C: public
B1, public
B2 { virtual
C* f (); };
int main() { return
0; }
用命令
g++ -fdump-class-hierarchy –o
test test.cc
,
gcc
将把关于类的信息转储到一个转储文件(如:
test.01.class
)中,我们可以看到如下的输出(暂时忽略布局以外的信息):
…
Class A
size=4 align=4
base size=4 base align=4
A (0xb7f2d680) 0 nearly-empty
vptr=((& A::_ZTV1A) + 8u)
…
Class B1
size=4 align=4
base size=4 base align=4
B1 (0xb7f2d700) 0 nearly-empty
vptridx=0u vptr=((& B1::_ZTV2B1) + 16u)
A (0xb7f2d740) 0 nearly-empty virtual
primary-for B1 (0xb7f2d700)
vptridx=4u vbaseoffset=-0x000000010
…
Class B2
size=4 align=4
base size=4 base align=4
B2 (0xb7f2d840) 0 nearly-empty
vptridx=0u vptr=((& B2::_ZTV2B2) + 16u)
A (0xb7f2d880) 0 nearly-empty virtual
primary-for B2 (0xb7f2d840)
vptridx=4u vbaseoffset=-0x000000010
…
Class C
size=8 align=4
base size=8 base align=4
C (0xb7f2d940) 0
vptridx=0u vptr=((& C::_ZTV1C) + 16u)
B1 (0xb7f2d980) 0 nearly-empty
primary-for C (0xb7f2d940)
subvttidx=4u
A (0xb7f2d9c0)
0 nearly-empty virtual
primary-for B1 (0xb7f2d980)
vptridx=20u vbaseoffset=-0x000000010
B2 (0xb7f2da00) 4 nearly-empty
lost-primary
subvttidx=12u vptridx=24u vptr=((& C::_ZTV1C) + 40u)
A (0xb7f2d9c0)
alternative-path
在输出“
A (0xb7f2d680) 0 nearly-empty
”中,“
A
”是
binfo
所来自的类,“
(0xb7f2d680)
”是
binfo
的地址,“
0
”是
binfo
在类布局中的偏移量,“
nearly-empty
”表明该类是一个几乎空的类。
而输出“
size=8 align=4
”是该类的大小及对齐量,而“
base size=8 base
align=4
”是该类的
CLASSTYPE_AS_BASE
(去除虚拟基类)的大小及对齐量。
例
2
(在类
A
中增加域“
int a
”):
class
A { int a; virtual
A* f (); };
class
B1 : virtual
public
A { virtual
B1* f (); };
class
B2 : virtual
public
A { virtual
B2* f (); };
class
C: public
B1, public
B2 { virtual
C* f (); };
int main() { return
0; }
其输出则是:
…
Class A
size=8 align=4
base size=8 base align=4
A (0xb7fae680)
0
vptr=((& A::_ZTV1A) + 8u)
…
Class B1
size=12 align=4
base size=4 base align=4
B1
(0xb7fae700) 0 nearly-empty
vptridx=0u vptr=((& B1::_ZTV2B1) + 12u)
A (0xb7fae740) 4 virtual
vptridx=4u vbaseoffset=-0x00000000c vptr=((& B1::_ZTV2B1) + 28u)
…
Class B2
size=12 align=4
base size=4 base align=4
B2
(0xb7fae800) 0 nearly-empty
vptridx=0u vptr=((& B2::_ZTV2B2) + 12u)
A (0xb7fae840) 4 virtual
vptridx=4u vbaseoffset=-0x00000000c vptr=((& B2::_ZTV2B2) + 28u)
…
Class C
size=16 align=4
base size=8 base align=4
C (0xb7fae8c0) 0
vptridx=0u vptr=((& C::_ZTV1C) + 12u)
B1
(0xb7fae900) 0 nearly-empty
primary-for C (0xb7fae8c0)
subvttidx=4u
A (0xb7fae940) 8 virtual
vptridx=20u vbaseoffset=-0x00000000c vptr=((& C::_ZTV1C) + 44u)
B2 (0xb7fae980) 4 nearly-empty
subvttidx=12u vptridx=24u vptr=((&
C::_ZTV1C) + 28u)
A (0xb7fae940) alternative-path
通过引入域“
int a
“,类
A
不再是一个几乎空的类,但
B1
及
B2
还是。这一事实深刻地影响着布局。在下面的代码中我们可以找到其原因。
4637
static
void
4638
layout_class_type
(tree t, tree
*virtuals_p)
in class.c
4639
{
4640
tree non_static_data_members;
4641
tree field;
4642
tree vptr;
4643
record_layout_info
rli;
4644
/* Maps offsets
(represented as INTEGER_CSTs) to a TREE_LIST of
4645
types that appear at that
offset.
*/
4646
splay_tree empty_base_offsets;
4647
/* True if the last
field layed out was a bit-field.
*/
4648
bool last_field_was_bitfield = false;
4649
/* The location at
which the next field should be inserted.
*/
4650
tree *next_field;
4651
/* T, as a base
class.
*/
4652
tree base_t;
4653
4654
/* Keep track of
the first non-static data member.
*/
4655
non_static_data_members = TYPE_FIELDS (t);
4656
4657
/* Start laying out
the record.
*/
4658
rli = start_record_layout
(t);
4659
4660
/* If possible, we
reuse the virtual function table pointer from one
4661
of our base classes.
*/
4662
determine_primary_base
(t);
在多继承的情况下,在派生类中基类将被依次编排。第一个基类有偏移量
0
,无疑可以从派生类的头部直接访问其成员,而其它随后的基类,要访问其成员,其成员的偏移量要加上基类本身到派生类头部的偏移量,等于包含了一个额外的间接寻址。加上深度继承的情形,需要仔细选择第一个编排的基类。注意到这里每个类定义都调用了
determine_primary_base
。如果我们为一个复杂类来调用它,其基类应该已经被这个函数处理过了。
1267
static
void
1268
determine_primary_base
(tree t)
in
class.c
1269
{
1270
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
1271
tree vbases;
1272
tree type_binfo;
1273
1274
/* If there are no
baseclasses, there is certainly no primary base.
*/
1275
if (n_baseclasses == 0)
1276
return
;
1277
1278
type_binfo = TYPE_BINFO (t);
1279
1280
for
(i = 0; i
< n_baseclasses; i++)
1281
{
1282
tree base_binfo = BINFO_BASETYPE
(type_binfo, i);
1283
tree basetype = BINFO_TYPE (base_binfo);
1284
1285
if (TYPE_CONTAINS_VPTR_P (basetype))
1286
{
1287
/* We prefer a
non-virtual base, although a virtual one will
1288
do.
*/
1289
if (TREE_VIA_VIRTUAL (base_binfo))
1290
continue
;
1291
1292
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
1293
{
1294
set_primary_base
(t, base_binfo);
1295
CLASSTYPE_VFIELDS (t) = copy_list
(CLASSTYPE_VFIELDS (basetype));
1296
}
1297
else
1298
{
1299
tree vfields;
1300
1301
/* Only add
unique vfields, and flatten them out as we go.
*/
1302
for
(vfields = CLASSTYPE_VFIELDS (basetype);
1303
vfields;
1304
vfields = TREE_CHAIN (vfields))
1305
if (VF_BINFO_VALUE (vfields) ==
NULL_TREE
1306
|| ! TREE_VIA_VIRTUAL
(VF_BINFO_VALUE (vfields)))
1307
CLASSTYPE_VFIELDS (t)
1308
= tree_cons (base_binfo,
1309
VF_BASETYPE_VALUE
(vfields),
1310
CLASSTYPE_VFIELDS
(t));
1311
}
1312
}
1313
}
含有
vtable
的非虚拟基类是最好的选择。碰到的第一个这样的基类被下面的
set_primary_base
与派生类绑定起来。注意
TYPE_VFIELD
是由编译器产生的指向
vtable
的域。
1253
static
void
1254
set_primary_base
(tree t, tree binfo)
in
class.c
1255
{
1256
tree basetype;
1257
1258
CLASSTYPE_PRIMARY_BINFO (t) = binfo;
1259
basetype = BINFO_TYPE (binfo);
1260
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE
(basetype);
1261
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS
(basetype);
1262
TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
1263
}
上面的域
CLASSTYPE_VFIELDS
是这个类型所持有的
vtable
链表(主要及次要
vtable
)。其节点中的
TREE_VALUE
是引入这个
vtable
的类型。对于引入该
vtable
,或从其主要基类继承该
vtable
的类,节点的
TREE_PURPOSE
则是
NULL
。对于其它
vtable
(来自次要基类),其节点的
TREE_PURPOSE
是该
vtable
所来自的基类的
BINFO
。
注意派生类的
CLASSTYPE_VFIELDS
开始是空的;而且虚拟基类,除非它几乎是空的(这时它不可能有
vtable
),是不能作为派生类的主要基类(就算它是唯一有
vtable
的基类)。因此上面对
vtable
的拷贝能确保只对非虚拟基类进行。并且注意如果是主要基类,派生类直接拷贝其
CLASSTYPE_VFIELDS
(用于这个主要基类
vtable
的节点的
PURPOSE
域为
NULL
)。这是因为主要基类就在派生类的头部,如果其有
vtable
,这个
vtable
的地址也就是派生类
vtable
所在地址,派生类将直接把这个
vtable
据为己有。
determine_primary_base (continue)
1315
if (!TYPE_VFIELD (t))
1316
CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
1317
1318
/* Find the
indirect primary bases - those virtual bases which are primary
1319
bases of something else in
this hierarchy.
*/
1320
for
(vbases = CLASSTYPE_VBASECLASSES (t);
1321
vbases;
1322
vbases = TREE_CHAIN (vbases))
1323
{
1324
tree vbase_binfo = TREE_VALUE (vbases);
1325
1326
/* See if this
virtual base is an indirect primary base. To be so,
1327
it must be a primary base
within the hierarchy of one of our
1328
direct bases.
*/
1329
for
(i = 0;
i < n_baseclasses; ++i)
1330
{
1331
tree basetype = TYPE_BINFO_BASETYPE (t,
i);
1332
tree v;
1333
1334
for
(v =
CLASSTYPE_VBASECLASSES (basetype);
1335
v;
1336
v = TREE_CHAIN (v))
1337
{
1338
tree base_vbase = TREE_VALUE (v);
1339
1340
if (BINFO_PRIMARY_P (base_vbase)
1341
&& same_type_p (BINFO_TYPE
(base_vbase),
1342
BINFO_TYPE (vbase_binfo)))
1343
{
1344
BINFO_INDIRECT_PRIMARY_P
(vbase_binfo) = 1;
1345
break
;
1346
}
1347
}
1348
1349
/* If we've
discovered that this virtual base is an indirect
1350
primary base, then we can move on to the
next virtual
1351
base.
*/
1352
if (BINFO_INDIRECT_PRIMARY_P
(vbase_binfo))
1353
break
;
1354
}
1355
}
1356
1357
/* A
"nearly-empty" virtual base class can be the primary base
1358
class, if no non-virtual polymorphic
base can be found.
*/
1359
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
1360
{
1361
/* If not NULL,
this is the best primary base candidate we have
1362
found so far.
*/
1363
tree candidate = NULL_TREE;
1364
tree base_binfo;
1365
1366
/* Loop over the
baseclasses.
*/
1367
for
(base_binfo = TYPE_BINFO (t);
1368
base_binfo;
1369
base_binfo = TREE_CHAIN (base_binfo))
1370
{
1371
tree basetype = BINFO_TYPE (base_binfo);
1372
1373
if (TREE_VIA_VIRTUAL (base_binfo)
1374
&& CLASSTYPE_NEARLY_EMPTY_P
(basetype))
1375
{
1376
/* If this is not an indirect primary base,
then it's
1377
definitely our primary
base.
*/
1378
if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
1379
{
1380
candidate = base_binfo;
1381
break
;
1382
}
1383
1384
/* If this is
an indirect primary base, it still could be
1385
our primary base --
unless we later find there's another
1386
nearly-empty virtual base that isn't an
indirect
1387
primary base.
*/
1388
if (!candidate)
1389
candidate = base_binfo;
1390
}
1391
}
1392
1393
/* If we've got a
primary base, use it.
*/
1394
if (candidate)
1395
{
1396
set_primary_base
(t, candidate);
1397
CLASSTYPE_VFIELDS (t)
1398
= copy_list (CLASSTYPE_VFIELDS
(BINFO_TYPE (candidate)));
1399
}
1400
}
1401
1402
/* Mark the primary
base classes at this point.
*/
1403
mark_primary_bases
(t);
1404
}
如果没有找到含有
vtable
的非虚拟基类,派生类的
TYPE_VFIELD
保持为
NULL
(在
set_primary base
中,它会被设置为主要基类的
TYPE_VFIELD
),这时不管以前把
CLASSTYPE_PRIMARY_BINFO
设置成什么,把它置为
NULL
。接着看看能不能在虚拟基类中找到可以作为主要基类的。能作为主要基类的虚拟基类,除了需要是几乎空的之外,没有被用作其基类的主要基类是优先考虑的,否则就将就使用在派生类声明中最后出现的虚拟基类(这样也减少了冲突的机会)。
严格来说,在一个派生类中只有一个主要基类。例如:
class
A {…}; class
B: public
A {…}; class
C: public
B {…};
此中类
B
的主要基类是
A
。而在类
C
中,主要基类是
B
,不再是
A
。但是
C
中关于
B
的
binfo
是从类
B
中拷贝过来的,拷贝时没有拷入关于主要基类的信息。不过虚拟基类则不然,下面的函数还会对它进行“拨乱反正”。
1218
static
void
1219
mark_primary_bases
(tree type)
in
class.c
1220
{
1221
tree binfo;
1222
1223
/* Walk the bases
in inheritance graph order.
*/
1224
for
(binfo =
TYPE_BINFO (type); binfo; binfo = TREE_CHAIN (binfo))
1225
{
1226
tree base_binfo = get_primary_binfo
(binfo);
1227
1228
if (!base_binfo)
1229
/* Not a
dynamic base.
*/
;
1230
else if (BINFO_PRIMARY_P (base_binfo))
1231
BINFO_LOST_PRIMARY_P (binfo) = 1;
1232
else
1233
{
1234
BINFO_PRIMARY_BASE_OF (base_binfo) =
binfo;
1235
/* A virtual
binfo might have been copied from within
1236
another hierarchy. As we're about to use
it as a primary
1237
base, make
sure the offsets match.
*/
1238
if (TREE_VIA_VIRTUAL (base_binfo))
1239
{
1240
tree delta = size_diffop (convert
(ssizetype,
1241
BINFO_OFFSET
(binfo)),
1242
convert (ssizetype,
1243
BINFO_OFFSET
(base_binfo)));
1244
1245
propagate_binfo_offsets
(base_binfo, delta);
1246
}
1247
}
1248
}
1249
}
在
1226
行的
get_primary_binfo
返回参数
binfo
所对应类型的主要基类的
binfo
的拷贝,如果设置了主要基类的话;否则返回
NULL
。
6470
tree
6471
get_primary_binfo
(tree binfo)
in
class.c
6472
{
6473
tree primary_base;
6474
tree result;
6475
6476
primary_base = CLASSTYPE_PRIMARY_BINFO
(BINFO_TYPE (binfo));
6477
if (!primary_base)
6478
return
NULL_TREE;
6479
6480
result = copied_binfo
(primary_base, binfo);
6481
return
result;
6482
}
copied_binfo
根据给定的
primary_base
,从
binfo
中找出对应的部分。考虑以下例子:
class
A { virtual
… };
class
B: public
A { virtual
… };
class
C: public
A { virtual
… };
class
D: public
B, C { … };
首先,在
mark_primary_bases
的
1224
行,
TYPE_BINFO(D)
得到一个链表,其中依次是
D
à
B
à
A
à
C
à
A
。显然,
CLASSTYPE_PRIMARY_BINFO(D)
返回
B
的
binfo
拷贝(它由
set_primary_base
设置);然后在下面的
2578
行,递归进入
copied_binfo
并得到
D
的
binfo
,接着在
2581
行的
FOR
循环中,在
D
的基类
B
、
C
中查找,找出目标
B
。因为该
B
的
binfo
拷贝来自类
B
,
1230
行的
BINFO_PRIMARY_P (base_binfo)
返回
NULL
,这表示
B
不是主要基类(但现在是!)。因此在
1234
行,我们把它设为
D
的主要基类(注意与
CLASSTYPE_PRIMARY_BINFO
的区别)。
那么对于
B
的
binfo
,
A
是其主要基类。在
D
中查找
A
的
binfo
拷贝与查找
B
的
binfo
拷贝类似,除了在
D
中
A
同时出现在
B
及
C
中。不过查找的过程能保证找到的是
B
à
A
。因为
A
是类
B
的主要基类,但在
A
拷贝的
binfo
中,并没有设置
BINFO_PRIMARY_P
,它满足
1232
行条件,被设置为
B
的拷贝
binfo
的主要基类。
同样的我们可以得到
D
中
C
部分的
A
的
binfo
拷贝,并且它也没有设置
BINFO_PRIMARY_P
。
2556
tree
2557
copied_binfo
(tree binfo, tree here)
in
search.c
2558
{
2559
tree result = NULL_TREE;
2560
2561
if (TREE_VIA_VIRTUAL (binfo))
2562
{
2563
tree t;
2564
2565
for
(t = here; BINFO_INHERITANCE_CHAIN (t);
2566
t = BINFO_INHERITANCE_CHAIN (t))
2567
continue
;
2568
2569
result = purpose_member (BINFO_TYPE
(binfo),
2570
CLASSTYPE_VBASECLASSES (BINFO_TYPE (t)));
2571
result = TREE_VALUE (result);
2572
}
2573
else if (BINFO_INHERITANCE_CHAIN (binfo))
2574
{
2575
tree base_binfos;
2576
int
ix, n;
2577
2578
base_binfos = copied_binfo
(BINFO_INHERITANCE_CHAIN (binfo), here);
2579
base_binfos = BINFO_BASETYPES
(base_binfos);
2580
n = TREE_VEC_LENGTH (base_binfos);
2581
for
(ix =
0; ix != n; ix++)
2582
{
2583
tree base = TREE_VEC_ELT (base_binfos,
ix);
2584
2585
if (BINFO_TYPE (base) == BINFO_TYPE
(binfo))
2586
{
2587
result = base;
2588
break
;
2589
}
2590
}
2591
}
2592
else
2593
{
2594
my_friendly_assert (BINFO_TYPE (here) ==
BINFO_TYPE (binfo), 20030202);
2595
result = here;
2596
}
2597
2598
my_friendly_assert (result, 20030202);
2599
return
result;
2600
}
进一步考虑如下的例子:
class
A { virtual
…};
class
B: virtual
public
A { … };
class
C: virtual
public
A { … };
class
D: public
B, C { … };
在
TYPE_BINFO(D)
链表中,依次是
D
à
B
à
A
à
C
,因为
A
作为虚拟基类在
D
中只能维持一个实例。这个过程是几乎相同的,除了查找虚拟基类的
binfo
拷贝时,是从继承树顶开始向下,而不是从基类开始往上爬。另外,由于虚拟基类
A
不使用拷贝
binfo
,因此在
mark_primary_bases
中,它满足
1230
行条件。
在
copy_base_binfos
中,连同
binfo
拷贝的还有偏移量信息。不过这个偏移量是关于被拷贝的
binfo
。而作为主要基类,虚拟基类(也包括非虚拟基类)必须被放在布局的最前面(事实上紧跟着
vtable
)。这个调整由
propagate_binfo_offsets
来完成(对于非虚拟的基类
binfo
,它的偏移量一直是
0
,并且在当前类中编排该基类时,其非虚拟基类也维持着不变的相对偏移量)。
4355
static
void
4356
propagate_binfo_offsets
(tree binfo,
tree offset)
in
class.c
4357
{
4358
int i;
4359
tree primary_binfo;
4360
4361
/* Update BINFO's offset.
*/
4362
BINFO_OFFSET (binfo)
4363
= convert (sizetype,
4364
size_binop (PLUS_EXPR,
4365
convert (ssizetype,
BINFO_OFFSET (binfo)),
4366
offset));
4367
4368
/* Find the primary
base class.
*/
4369
primary_binfo = get_primary_binfo
(binfo);
4370
4371
/* Scan all of the
bases, pushing the BINFO_OFFSET adjust
4372
downwards.
*/
4373
for
(i = -1; i < BINFO_N_BASETYPES (binfo); ++i)
4374
{
4375
tree base_binfo;
4376
4377
/* On the first
time through the loop, do the primary base.
4378
Because the primary base
need not be an immediate base, we
4379
must handle the primary base
specially.
*/
4380
if (i == -1)
4381
{
4382
if (!primary_binfo)
4383
continue
;
4384
4385
base_binfo = primary_binfo;
4386
}
4387
else
4388
{
4389
base_binfo = BINFO_BASETYPE (binfo, i);
4390
/* Don't do the
primary base twice.
*/
4391
if (base_binfo == primary_binfo)
4392
continue
;
4393
}
4394
4395
/* Skip virtual
bases that aren't our canonical primary base.
*/
4396
if (TREE_VIA_VIRTUAL (base_binfo)
4397
&& BINFO_PRIMARY_BASE_OF
(base_binfo) != binfo)
4398
continue
;
4399
4400
propagate_binfo_offsets
(base_binfo, offset);
4401
}
4402
}
函数
propagate_binfo_offsets
把偏移量的调整应用到整个基类。记得
BINFO_OFFSET
表示该基类在其派生类中的偏移量。前面看到主要基类不一定是直接基类,因此
4373
行的
FOR
循环需要多一次计数来包括可能不是直接基类的主要基类。
完成派生类的
RECORD_TYPE
–
布局
回到
finish_struct_1
中,下面的
keyed_classes
是一个保存那些在这个编译单元中将可能发布
vtable
的类的
tree_list
。这个链表中的候选者是不含有非内联、非纯虚方法的类。换而言之,是仅含有纯虚方法或(及)内联虚方法的类。对于这样的类,在每个该类定义出现的编译单元中(如,通过
#include
),应该发布其
vtable
;而对于含有其它虚方法的类,每个包含了其虚方法定义的编译单元要发布其
vtable
。
finish_struct_1 (continue)
5033
/* Find the key
method.
*/
5034
if (TYPE_CONTAINS_VPTR_P (t))
5035
{
5036
CLASSTYPE_KEY_METHOD (t) = key_method
(t);
5037
5038
/* If a
polymorphic class has no key method, we may emit the vtable
5039
i
n every translation unit where the class
definition appears.
*/
5040
if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE)
5041
keyed_classes
= tree_cons (NULL_TREE, t, keyed_classes
);
5042
}
5043
5044
/* Layout the class
itself.
*/
5045
layout_class_type
(t, &virtuals);
5046
if (CLASSTYPE_AS_BASE (t) != t)
5047
/* We use the base type for trivial
assignments, and hence it
5048
needs a mode.
*/
5049
compute_record_mode
(CLASSTYPE_AS_BASE (t));
CLASSTYPE_KEY_METHOD
保存了类中第一个非内联及非纯虚方法
,这个域在
vtable
的产生过程中要用到。
4973
static
tree
4974
key_method
(tree type)
in class.c
4975
{
4976
tree method;
4977
4978
if (TYPE_FOR_JAVA (ty
pe)
4979
||
processing_template_decl
4980
||
CLASSTYPE_TEMPLATE_INSTANTIATION (type)
4981
||
CLASSTYPE_INTERFACE_KNOWN (type))
4982
return
NULL_TREE;
4983
4984
for
(method =
TYPE_METHODS (type); method != NULL_TREE;
4985
method = TREE_CHAIN (method))
4986
if (DECL_VINDEX (method) != NULL_TREE
4987
&& ! DECL_DECLARED_INLINE_P
(method)
4988
&& ! DECL_PURE_VIRTUAL_P
(method))
4989
return
method;
4990
4991
return
NULL_TREE;
4992
}
记住在类模板中是不允许出现虚函数的。
如果我们已经确定了是否要在该编译单元中产生
vtable
,
VTT
,
typeinfo
及其他类似的类维护数据,
CLASSTYPE_INTERFACE_KNOWN
是
true
,这样的类即便满足上述条件,也不应该被保存在
keyed_classes
中。
接着我们可以为类布局来决定类型的真正的大小,每个数据成员的偏移量,大小,填充字节,甚至由编译器产生的维护数据。毫无疑问,这是一个相当复杂的过程。
在深入到代码之前,我们首先看一下
GCC
为下面的例子所做的布局:
例
1
:
class
A { virtual
A* f (); };
class
B1 : virtual
public
A { virtual
B1* f (); };
class
B2 : virtual
public
A { virtual
B2* f (); };
class
C: public
B1, public
B2 { virtual
C* f (); };
int main() { return
0; }
用命令
g++ -fdump-class-hierarchy –o
test test.cc
,
gcc
将把关于类的信息转储到一个转储文件(如:
test.01.class
)中,我们可以看到如下的输出(暂时忽略布局以外的信息):
…
Class A
size=4 align=4
base size=4 base align=4
A (0xb7f2d680) 0 nearly-empty
vptr=((& A::_ZTV1A) + 8u)
…
Class B1
size=4 align=4
base size=4 base align=4
B1 (0xb7f2d700) 0 nearly-empty
vptridx=0u vptr=((& B1::_ZTV2B1) + 16u)
A (0xb7f2d740) 0 nearly-empty virtual
primary-for B1 (0xb7f2d700)
vptridx=4u vbaseoffset=-0x000000010
…
Class B2
size=4 align=4
base size=4 base align=4
B2 (0xb7f2d840) 0 nearly-empty
vptridx=0u vptr=((& B2::_ZTV2B2) + 16u)
A (0xb7f2d880) 0 nearly-empty virtual
primary-for B2 (0xb7f2d840)
vptridx=4u vbaseoffset=-0x000000010
…
Class C
size=8 align=4
base size=8 base align=4
C (0xb7f2d940) 0
vptridx=0u vptr=((& C::_ZTV1C) + 16u)
B1 (0xb7f2d980) 0 nearly-empty
primary-for C (0xb7f2d940)
subvttidx=4u
A (0xb7f2d9c0)
0 nearly-empty virtual
primary-for B1 (0xb7f2d980)
vptridx=20u vbaseoffset=-0x000000010
B2 (0xb7f2da00) 4 nearly-empty
lost-primary
subvttidx=12u vptridx=24u vptr=((& C::_ZTV1C) + 40u)
A (0xb7f2d9c0)
alternative-path
在输出“
A (0xb7f2d680) 0 nearly-empty
”中,“
A
”是
binfo
所来自的类,“
(0xb7f2d680)
”是
binfo
的地址,“
0
”是
binfo
在类布局中的偏移量,“
nearly-empty
”表明该类是一个几乎空的类。
而输出“
size=8 align=4
”是该类的大小及对齐量,而“
base size=8 base
align=4
”是该类的
CLASSTYPE_AS_BASE
(去除虚拟基类)的大小及对齐量。
例
2
(在类
A
中增加域“
int a
”):
class
A { int a; virtual
A* f (); };
class
B1 : virtual
public
A { virtual
B1* f (); };
class
B2 : virtual
public
A { virtual
B2* f (); };
class
C: public
B1, public
B2 { virtual
C* f (); };
int main() { return
0; }
其输出则是:
…
Class A
size=8 align=4
base size=8 base align=4
A (0xb7fae680)
0
vptr=((& A::_ZTV1A) + 8u)
…
Class B1
size=12 align=4
base size=4 base align=4
B1
(0xb7fae700) 0 nearly-empty
vptridx=0u vptr=((& B1::_ZTV2B1) + 12u)
A (0xb7fae740) 4 virtual
vptridx=4u vbaseoffset=-0x00000000c vptr=((& B1::_ZTV2B1) + 28u)
…
Class B2
size=12 align=4
base size=4 base align=4
B2
(0xb7fae800) 0 nearly-empty
vptridx=0u vptr=((& B2::_ZTV2B2) + 12u)
A (0xb7fae840) 4 virtual
vptridx=4u vbaseoffset=-0x00000000c vptr=((& B2::_ZTV2B2) + 28u)
…
Class C
size=16 align=4
base size=8 base align=4
C (0xb7fae8c0) 0
vptridx=0u vptr=((& C::_ZTV1C) + 12u)
B1
(0xb7fae900) 0 nearly-empty
primary-for C (0xb7fae8c0)
subvttidx=4u
A (0xb7fae940) 8 virtual
vptridx=20u vbaseoffset=-0x00000000c vptr=((& C::_ZTV1C) + 44u)
B2 (0xb7fae980) 4 nearly-empty
subvttidx=12u vptridx=24u vptr=((&
C::_ZTV1C) + 28u)
A (0xb7fae940) alternative-path
通过引入域“
int a
“,类
A
不再是一个几乎空的类,但
B1
及
B2
还是。这一事实深刻地影响着布局。在下面的代码中我们可以找到其原因。
4637
static
void
4638
layout_class_type
(tree t, tree
*virtuals_p)
in class.c
4639
{
4640
tree non_static_data_members;
4641
tree field;
4642
tree vptr;
4643
record_layout_info
rli;
4644
/* Maps offsets
(represented as INTEGER_CSTs) to a TREE_LIST of
4645
types that appear at that
offset.
*/
4646
splay_tree empty_base_offsets;
4647
/* True if the last
field layed out was a bit-field.
*/
4648
bool last_field_was_bitfield = false;
4649
/* The location at
which the next field should be inserted.
*/
4650
tree *next_field;
4651
/* T, as a base
class.
*/
4652
tree base_t;
4653
4654
/* Keep track of
the first non-static data member.
*/
4655
non_static_data_members = TYPE_FIELDS (t);
4656
4657
/* Start laying out
the record.
*/
4658
rli = start_record_layout
(t);
4659
4660
/* If possible, we
reuse the virtual function table pointer from one
4661
of our base classes.
*/
4662
determine_primary_base
(t);
在多继承的情况下,在派生类中基类将被依次编排。第一个基类有偏移量
0
,无疑可以从派生类的头部直接访问其成员,而其它随后的基类,要访问其成员,其成员的偏移量要加上基类本身到派生类头部的偏移量,等于包含了一个额外的间接寻址。加上深度继承的情形,需要仔细选择第一个编排的基类。注意到这里每个类定义都调用了
determine_primary_base
。如果我们为一个复杂类来调用它,其基类应该已经被这个函数处理过了。
1267
static
void
1268
determine_primary_base
(tree t)
in
class.c
1269
{
1270
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
1271
tree vbases;
1272
tree type_binfo;
1273
1274
/* If there are no
baseclasses, there is certainly no primary base.
*/
1275
if (n_baseclasses == 0)
1276
return
;
1277
1278
type_binfo = TYPE_BINFO (t);
1279
1280
for
(i = 0; i
< n_baseclasses; i++)
1281
{
1282
tree base_binfo = BINFO_BASETYPE
(type_binfo, i);
1283
tree basetype = BINFO_TYPE (base_binfo);
1284
1285
if (TYPE_CONTAINS_VPTR_P (basetype))
1286
{
1287
/* We prefer a
non-virtual base, although a virtual one will
1288
do.
*/
1289
if (TREE_VIA_VIRTUAL (base_binfo))
1290
continue
;
1291
1292
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
1293
{
1294
set_primary_base
(t, base_binfo);
1295
CLASSTYPE_VFIELDS (t) = copy_list
(CLASSTYPE_VFIELDS (basetype));
1296
}
1297
else
1298
{
1299
tree vfields;
1300
1301
/* Only add
unique vfields, and flatten them out as we go.
*/
1302
for
(vfields = CLASSTYPE_VFIELDS (basetype);
1303
vfields;
1304
vfields = TREE_CHAIN (vfields))
1305
if (VF_BINFO_VALUE (vfields) ==
NULL_TREE
1306
|| ! TREE_VIA_VIRTUAL
(VF_BINFO_VALUE (vfields)))
1307
CLASSTYPE_VFIELDS (t)
1308
= tree_cons (base_binfo,
1309
VF_BASETYPE_VALUE
(vfields),
1310
CLASSTYPE_VFIELDS
(t));
1311
}
1312
}
1313
}
含有
vtable
的非虚拟基类是最好的选择。碰到的第一个这样的基类被下面的
set_primary_base
与派生类绑定起来。注意
TYPE_VFIELD
是由编译器产生的指向
vtable
的域。
1253
static
void
1254
set_primary_base
(tree t, tree binfo)
in
class.c
1255
{
1256
tree basetype;
1257
1258
CLASSTYPE_PRIMARY_BINFO (t) = binfo;
1259
basetype = BINFO_TYPE (binfo);
1260
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE
(basetype);
1261
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS
(basetype);
1262
TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
1263
}
上面的域
CLASSTYPE_VFIELDS
是这个类型所持有的
vtable
链表(主要及次要
vtable
)。其节点中的
TREE_VALUE
是引入这个
vtable
的类型。对于引入该
vtable
,或从其主要基类继承该
vtable
的类,节点的
TREE_PURPOSE
则是
NULL
。对于其它
vtable
(来自次要基类),其节点的
TREE_PURPOSE
是该
vtable
所来自的基类的
BINFO
。
注意派生类的
CLASSTYPE_VFIELDS
开始是空的;而且虚拟基类,除非它几乎是空的(这时它不可能有
vtable
),是不能作为派生类的主要基类(就算它是唯一有
vtable
的基类)。因此上面对
vtable
的拷贝能确保只对非虚拟基类进行。并且注意如果是主要基类,派生类直接拷贝其
CLASSTYPE_VFIELDS
(用于这个主要基类
vtable
的节点的
PURPOSE
域为
NULL
)。这是因为主要基类就在派生类的头部,如果其有
vtable
,这个
vtable
的地址也就是派生类
vtable
所在地址,派生类将直接把这个
vtable
据为己有。
determine_primary_base (continue)
1315
if (!TYPE_VFIELD (t))
1316
CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
1317
1318
/* Find the
indirect primary bases - those virtual bases which are primary
1319
bases of something else in
this hierarchy.
*/
1320
for
(vbases = CLASSTYPE_VBASECLASSES (t);
1321
vbases;
1322
vbases = TREE_CHAIN (vbases))
1323
{
1324
tree vbase_binfo = TREE_VALUE (vbases);
1325
1326
/* See if this
virtual base is an indirect primary base. To be so,
1327
it must be a primary base
within the hierarchy of one of our
1328
direct bases.
*/
1329
for
(i = 0;
i < n_baseclasses; ++i)
1330
{
1331
tree basetype = TYPE_BINFO_BASETYPE (t,
i);
1332
tree v;
1333
1334
for
(v =
CLASSTYPE_VBASECLASSES (basetype);
1335
v;
1336
v = TREE_CHAIN (v))
1337
{
1338
tree base_vbase = TREE_VALUE (v);
1339
1340
if (BINFO_PRIMARY_P (base_vbase)
1341
&& same_type_p (BINFO_TYPE
(base_vbase),
1342
BINFO_TYPE (vbase_binfo)))
1343
{
1344
BINFO_INDIRECT_PRIMARY_P
(vbase_binfo) = 1;
1345
break
;
1346
}
1347
}
1348
1349
/* If we've
discovered that this virtual base is an indirect
1350
primary base, then we can move on to the
next virtual
1351
base.
*/
1352
if (BINFO_INDIRECT_PRIMARY_P
(vbase_binfo))
1353
break
;
1354
}
1355
}
1356
1357
/* A
"nearly-empty" virtual base class can be the primary base
1358
class, if no non-virtual polymorphic
base can be found.
*/
1359
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
1360
{
1361
/* If not NULL,
this is the best primary base candidate we have
1362
found so far.
*/
1363
tree candidate = NULL_TREE;
1364
tree base_binfo;
1365
1366
/* Loop over the
baseclasses.
*/
1367
for
(base_binfo = TYPE_BINFO (t);
1368
base_binfo;
1369
base_binfo = TREE_CHAIN (base_binfo))
1370
{
1371
tree basetype = BINFO_TYPE (base_binfo);
1372
1373
if (TREE_VIA_VIRTUAL (base_binfo)
1374
&& CLASSTYPE_NEARLY_EMPTY_P
(basetype))
1375
{
1376
/* If this is not an indirect primary base,
then it's
1377
definitely our primary
base.
*/
1378
if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
1379
{
1380
candidate = base_binfo;
1381
break
;
1382
}
1383
1384
/* If this is
an indirect primary base, it still could be
1385
our primary base --
unless we later find there's another
1386
nearly-empty virtual base that isn't an
indirect
1387
primary base.
*/
1388
if (!candidate)
1389
candidate = base_binfo;
1390
}
1391
}
1392
1393
/* If we've got a
primary base, use it.
*/
1394
if (candidate)
1395
{
1396
set_primary_base
(t, candidate);
1397
CLASSTYPE_VFIELDS (t)
1398
= copy_list (CLASSTYPE_VFIELDS
(BINFO_TYPE (candidate)));
1399
}
1400
}
1401
1402
/* Mark the primary
base classes at this point.
*/
1403
mark_primary_bases
(t);
1404
}
如果没有找到含有
vtable
的非虚拟基类,派生类的
TYPE_VFIELD
保持为
NULL
(在
set_primary base
中,它会被设置为主要基类的
TYPE_VFIELD
),这时不管以前把
CLASSTYPE_PRIMARY_BINFO
设置成什么,把它置为
NULL
。接着看看能不能在虚拟基类中找到可以作为主要基类的。能作为主要基类的虚拟基类,除了需要是几乎空的之外,没有被用作其基类的主要基类是优先考虑的,否则就将就使用在派生类声明中最后出现的虚拟基类(这样也减少了冲突的机会)。
严格来说,在一个派生类中只有一个主要基类。例如:
class
A {…}; class
B: public
A {…}; class
C: public
B {…};
此中类
B
的主要基类是
A
。而在类
C
中,主要基类是
B
,不再是
A
。但是
C
中关于
B
的
binfo
是从类
B
中拷贝过来的,拷贝时没有拷入关于主要基类的信息。不过虚拟基类则不然,下面的函数还会对它进行“拨乱反正”。
1218
static
void
1219
mark_primary_bases
(tree type)
in
class.c
1220
{
1221
tree binfo;
1222
1223
/* Walk the bases
in inheritance graph order.
*/
1224
for
(binfo =
TYPE_BINFO (type); binfo; binfo = TREE_CHAIN (binfo))
1225
{
1226
tree base_binfo = get_primary_binfo
(binfo);
1227
1228
if (!base_binfo)
1229
/* Not a
dynamic base.
*/
;
1230
else if (BINFO_PRIMARY_P (base_binfo))
1231
BINFO_LOST_PRIMARY_P (binfo) = 1;
1232
else
1233
{
1234
BINFO_PRIMARY_BASE_OF (base_binfo) =
binfo;
1235
/* A virtual
binfo might have been copied from within
1236
another hierarchy. As we're about to use
it as a primary
1237
base, make
sure the offsets match.
*/
1238
if (TREE_VIA_VIRTUAL (base_binfo))
1239
{
1240
tree delta = size_diffop (convert
(ssizetype,
1241
BINFO_OFFSET
(binfo)),
1242
convert (ssizetype,
1243
BINFO_OFFSET
(base_binfo)));
1244
1245
propagate_binfo_offsets
(base_binfo, delta);
1246
}
1247
}
1248
}
1249
}
在
1226
行的
get_primary_binfo
返回参数
binfo
所对应类型的主要基类的
binfo
的拷贝,如果设置了主要基类的话;否则返回
NULL
。
6470
tree
6471
get_primary_binfo
(tree binfo)
in
class.c
6472
{
6473
tree primary_base;
6474
tree result;
6475
6476
primary_base = CLASSTYPE_PRIMARY_BINFO
(BINFO_TYPE (binfo));
6477
if (!primary_base)
6478
return
NULL_TREE;
6479
6480
result = copied_binfo
(primary_base, binfo);
6481
return
result;
6482
}
copied_binfo
根据给定的
primary_base
,从
binfo
中找出对应的部分。考虑以下例子:
class
A { virtual
… };
class
B: public
A { virtual
… };
class
C: public
A { virtual
… };
class
D: public
B, C { … };
首先,在
mark_primary_bases
的
1224
行,
TYPE_BINFO(D)
得到一个链表,其中依次是
D
à
B
à
A
à
C
à
A
。显然,
CLASSTYPE_PRIMARY_BINFO(D)
返回
B
的
binfo
拷贝(它由
set_primary_base
设置);然后在下面的
2578
行,递归进入
copied_binfo
并得到
D
的
binfo
,接着在
2581
行的
FOR
循环中,在
D
的基类
B
、
C
中查找,找出目标
B
。因为该
B
的
binfo
拷贝来自类
B
,
1230
行的
BINFO_PRIMARY_P (base_binfo)
返回
NULL
,这表示
B
不是主要基类(但现在是!)。因此在
1234
行,我们把它设为
D
的主要基类(注意与
CLASSTYPE_PRIMARY_BINFO
的区别)。
那么对于
B
的
binfo
,
A
是其主要基类。在
D
中查找
A
的
binfo
拷贝与查找
B
的
binfo
拷贝类似,除了在
D
中
A
同时出现在
B
及
C
中。不过查找的过程能保证找到的是
B
à
A
。因为
A
是类
B
的主要基类,但在
A
拷贝的
binfo
中,并没有设置
BINFO_PRIMARY_P
,它满足
1232
行条件,被设置为
B
的拷贝
binfo
的主要基类。
同样的我们可以得到
D
中
C
部分的
A
的
binfo
拷贝,并且它也没有设置
BINFO_PRIMARY_P
。
2556
tree
2557
copied_binfo
(tree binfo, tree here)
in
search.c
2558
{
2559
tree result = NULL_TREE;
2560
2561
if (TREE_VIA_VIRTUAL (binfo))
2562
{
2563
tree t;
2564
2565
for
(t = here; BINFO_INHERITANCE_CHAIN (t);
2566
t = BINFO_INHERITANCE_CHAIN (t))
2567
continue
;
2568
2569
result = purpose_member (BINFO_TYPE
(binfo),
2570
CLASSTYPE_VBASECLASSES (BINFO_TYPE (t)));
2571
result = TREE_VALUE (result);
2572
}
2573
else if (BINFO_INHERITANCE_CHAIN (binfo))
2574
{
2575
tree base_binfos;
2576
int
ix, n;
2577
2578
base_binfos = copied_binfo
(BINFO_INHERITANCE_CHAIN (binfo), here);
2579
base_binfos = BINFO_BASETYPES
(base_binfos);
2580
n = TREE_VEC_LENGTH (base_binfos);
2581
for
(ix =
0; ix != n; ix++)
2582
{
2583
tree base = TREE_VEC_ELT (base_binfos,
ix);
2584
2585
if (BINFO_TYPE (base) == BINFO_TYPE
(binfo))
2586
{
2587
result = base;
2588
break
;
2589
}
2590
}
2591
}
2592
else
2593
{
2594
my_friendly_assert (BINFO_TYPE (here) ==
BINFO_TYPE (binfo), 20030202);
2595
result = here;
2596
}
2597
2598
my_friendly_assert (result, 20030202);
2599
return
result;
2600
}
进一步考虑如下的例子:
class
A { virtual
…};
class
B: virtual
public
A { … };
class
C: virtual
public
A { … };
class
D: public
B, C { … };
在
TYPE_BINFO(D)
链表中,依次是
D
à
B
à
A
à
C
,因为
A
作为虚拟基类在
D
中只能维持一个实例。这个过程是几乎相同的,除了查找虚拟基类的
binfo
拷贝时,是从继承树顶开始向下,而不是从基类开始往上爬。另外,由于虚拟基类
A
不使用拷贝
binfo
,因此在
mark_primary_bases
中,它满足
1230
行条件。
在
copy_base_binfos
中,连同
binfo
拷贝的还有偏移量信息。不过这个偏移量是关于被拷贝的
binfo
。而作为主要基类,虚拟基类(也包括非虚拟基类)必须被放在布局的最前面(事实上紧跟着
vtable
)。这个调整由
propagate_binfo_offsets
来完成(对于非虚拟的基类
binfo
,它的偏移量一直是
0
,并且在当前类中编排该基类时,其非虚拟基类也维持着不变的相对偏移量)。
4355
static
void
4356
propagate_binfo_offsets
(tree binfo,
tree offset)
in
class.c
4357
{
4358
int i;
4359
tree primary_binfo;
4360
4361
/* Update BINFO's offset.
*/
4362
BINFO_OFFSET (binfo)
4363
= convert (sizetype,
4364
size_binop (PLUS_EXPR,
4365
convert (ssizetype,
BINFO_OFFSET (binfo)),
4366
offset));
4367
4368
/* Find the primary
base class.
*/
4369
primary_binfo = get_primary_binfo
(binfo);
4370
4371
/* Scan all of the
bases, pushing the BINFO_OFFSET adjust
4372
downwards.
*/
4373
for
(i = -1; i < BINFO_N_BASETYPES (binfo); ++i)
4374
{
4375
tree base_binfo;
4376
4377
/* On the first
time through the loop, do the primary base.
4378
Because the primary base
need not be an immediate base, we
4379
must handle the primary base
specially.
*/
4380
if (i == -1)
4381
{
4382
if (!primary_binfo)
4383
continue
;
4384
4385
base_binfo = primary_binfo;
4386
}
4387
else
4388
{
4389
base_binfo = BINFO_BASETYPE (binfo, i);
4390
/* Don't do the
primary base twice.
*/
4391
if (base_binfo == primary_binfo)
4392
continue
;
4393
}
4394
4395
/* Skip virtual
bases that aren't our canonical primary base.
*/
4396
if (TREE_VIA_VIRTUAL (base_binfo)
4397
&& BINFO_PRIMARY_BASE_OF
(base_binfo) != binfo)
4398
continue
;
4399
4400
propagate_binfo_offsets
(base_binfo, offset);
4401
}
4402
}
函数
propagate_binfo_offsets
把偏移量的调整应用到整个基类。记得
BINFO_OFFSET
表示该基类在其派生类中的偏移量。前面看到主要基类不一定是直接基类,因此
4373
行的
FOR
循环需要多一次计数来包括可能不是直接基类的主要基类。
相关文章推荐
- GCC-3.4.6源代码学习笔记(139-续2)
- GCC-3.4.6源代码学习笔记(139-续1)
- GCC-3.4.6源代码学习笔记(45)
- GCC-3.4.6源代码学习笔记(140 - 续)
- GCC-3.4.6源代码学习笔记 当前目录
- GCC-3.4.6源代码学习笔记(94)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记(72)
- GCC-3.4.6源代码学习笔记(40)
- GCC-3.4.6源代码学习笔记(51)
- GCC-3.4.6源代码学习笔记(119)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(82)
- GCC-3.4.6源代码学习笔记(165)
- GCC-3.4.6源代码学习笔记(112)
- GCC-3.4.6源代码学习笔记(61)
- GCC-3.4.6源代码学习笔记(31)
- GCC-3.4.6源代码学习笔记(37)
- GCC-3.4.6源代码学习笔记(149)
- GCC-3.4.6源代码学习笔记(48续)