好了,现在让我们看一下 GCC 对我们例 1 的输出。
例 1 :
Vtable for C
C::_ZTV1C: 12u entries
0 0u // vbase offset
4 0u // vcall offset
8 (int (*)(...))0
12 (int (*)(...))(& _ZTI1C)
16 C ::_ZTcv0_n12_v0_n16_N1C1fEv // slot for C::B1::A::f
20 C ::f // slot for C::f
24 -4u
28 -4u
32 (int (*)(...))-0x000000004
36 (int (*)(...))(& _ZTI1C)
40 C ::_ZTcvn4_n12_v0_n16_N1C1fEv // slot for C::B2::A::f
44 C ::_ZTchn4_h4_N1C1fEv // slot for C::B2::f
… // no VTT for A
VTT for B1
B1::_ZTT2B1: 2u entries
0 ((& B1::_ZTV2B1) + 16u)
4 ((& B1::_ZTV2B1) + 16u)
…
VTT for B2
B2::_ZTT2B2: 2u entries
0 ((& B2::_ZTV2B2) + 16u)
4 ((& B2::_ZTV2B2) + 16u)
…
Construction vtable for B1 (0xb7f2d980 instance) in C
C::_ZTC1C0_2B1: 6u entries
0 0u
4 0u
8 (int (*)(...))0
12 (int (*)(...))(& _ZTI2B1)
16 B1::_ZTcv0_n12_v0_n16_N2B11fEv // C::B1::f
20 B1::f
Construction vtable for B2 (0xb7f2da00 instance) in C
C::_ZTC1C4_2B2: 10u entries
0 -4u
4 0u
8 (int (*)(...))0
12 (int (*)(...))(& _ZTI2B2)
16 B2::_ZTcv0_n12_v0_n16_N2B21fEv // C::B2::f
20 B2::f
24 4u
28 (int (*)(...))4
32 (int (*)(...))(& _ZTI2B2)
36 B2::_ZTcv0_n12_v0_n16_N2B21fEv // C::B2::f
VTT for C
C::_ZTT1C: 7u entries
0 ((& C::_ZTV1C) + 16u) // vptr for C
4 ((& C::_ZTC1C0_2B1) + 16u) // construction vtable used for B1
8 ((& C::_ZTC1C0_2B1) + 16u) // construction vtable used for B1::A
12 ((& C::_ZTC1C4_2B2) + 16u) // construction vtable used for B2
16 ((& C::_ZTC1C4_2B2) + 36u) // construction vtable used for B2::A
20 ((& C::_ZTV1C) + 16u) // vptr for secondary vtable of B2
24 ((& C::_ZTV1C) + 40u) // vptr for secondary vtable of A
VTT 的构造由下面的函数完成。
6829 static void
6830 build_vtt (tree t) in class.c
6831 {
6832 tree inits;
6833 tree type;
6834 tree vtt;
6835 tree index;
6836
6837 /* Build up the initializers for the VTT. */
6838 inits = NULL_TREE;
6839 index = size_zero_node;
6840 build_vtt_inits (TYPE_BINFO (t), t, &inits, &index);
6841
6842 /* If we didn't need a VTT, we're done. */
6843 if (!inits)
6844 return ;
6845
6846 /* Figure out the type of the VTT. */
6847 type = build_index_type (size_int (list_length (inits) - 1));
6848 type = build_cplus_array_type (const_ptr_type_node, type);
6849
6850 /* Now, build the VTT object itself. */
6851 vtt = build_vtable (t, get_vtt_name (t), type);
6852 initialize_array (vtt, inits);
6853 /* Add the VTT to the vtables list. */
6854 TREE_CHAIN (vtt) = TREE_CHAIN (CLASSTYPE_VTABLES (t));
6855 TREE_CHAIN (CLASSTYPE_VTABLES (t)) = vtt;
6856
6857 dump_vtt (t, vtt);
6858 }
在我们的例子中 , 对于类 B1 , B2 及 C , VTT 是期望的 , 其主体由下面的 build_vtt_init 构建。其中参数 binfo 是最后派生类的 binfo , t 是最后派生类 , 而 index 是在 VTT 中最后占用的索引。
6892 static tree *
6893 build_vtt_inits (tree binfo, tree t, tree* inits, tree* index) in class.c
6894 {
6895 int i;
6896 tree b;
6897 tree init;
6898 tree secondary_vptrs;
6899 int top_level_p = same_type_p (TREE_TYPE (binfo), t);
6900
6901 /* We only need VTTs for subobjects with virtual bases. */
6902 if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
6903 return inits;
6904
6905 /* We need to use a construction vtable if this is not the primary
6906 VTT. */
6907 if (!top_level_p)
6908 {
6909 build_ctor_vtbl_group (binfo, t);
6910
6911 /* Record the offset in the VTT where this sub-VTT can be found. */
6912 BINFO_SUBVTT_INDEX (binfo) = *index;
6913 }
6914
6915 /* Add the address of the primary vtable for the complete object. */
6916 init = binfo_ctor_vtable (binfo);
6917 *inits = build_tree_list (NULL_TREE, init);
6918 inits = &TREE_CHAIN (*inits);
6919 if (top_level_p)
6920 {
6921 my_friendly_assert (!BINFO_VPTR_INDEX (binfo), 20010129);
6922 BINFO_VPTR_INDEX (binfo) = *index;
6923 }
6924 *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));
6925
6926 /* Recursively add the secondary VTTs for non-virtual bases. */
6927 for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
6928 {
6929 b = BINFO_BASETYPE (binfo, i);
6930 if (!TREE_VIA_VIRTUAL (b))
6931 inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t,
6932 inits, index);
6933 }
在前一节中,类的 BINFO_VTABLE 在 dfs_accumulate_vtbl_inits 中设置了 vtable 初始值。它是一个 PLUS_EXPR ,指定了作为 vtable 开头的初始值的位置。在上面的 6916 行, binfo_ctor_vtable 从类得到这个表达式。
6865 static tree
6866 binfo_ctor_vtable (tree binfo) in class.c
6867 {
6868 tree vt;
6869
6870 while (1)
6871 {
6872 vt = BINFO_VTABLE (binfo);
6873 if (TREE_CODE (vt) == TREE_LIST)
6874 vt = TREE_VALUE (vt);
6875 if (TREE_CODE (vt) == TREE_VEC)
6876 binfo = vt;
6877 else
6878 break ;
6879 }
6880
6881 return vt;
6882 }
在上面的 6917 行,由 binfo_ctor_vtable 返回的 init 被构建入一个 tree_list ;而在 6918 行, inits 又指向了这个 tree_list 的 chain 域的地址,那么在 6931 行递归进入这个函数时,将继续往这个链表上添加节点。上面的参数 index 是 VTT 中下一个成员的索引(它也是字节数),一开始它为 size_zero_node 。
在 6922 行的 BINFO_VPTR_INDEX 保存了 VTT 的索引,在那里可以找到该子对象的虚指针。对于最后派生类 C ,其虚指针在 VTT 索引为 0 的地方。首先,对非虚拟基类, build_ctor_vtbl_group 执行以下的处理。
7098 static void
7099 build_ctor_vtbl_group (tree binfo, tree t) in class.c
7100 {
7101 tree list;
7102 tree type;
7103 tree vtbl;
7104 tree inits;
7105 tree id;
7106 tree vbase;
7107
7108 /* See if we've already created this construction vtable group. */
7109 id = mangle_ctor_vtbl_for_type (t, binfo);
7110 if (IDENTIFIER_GLOBAL_VALUE (id))
7111 return ;
7112
7113 my_friendly_assert (!same_type_p (BINFO_TYPE (binfo), t), 20010124);
7114 /* Build a version of VTBL (with the wrong type) for use in
7115 constructing the addresses of secondary vtables in the
7116 construction vtable group. */
7117 vtbl = build_vtable (t, id, ptr_type_node);
7118 list = build_tree_list (vtbl, NULL_TREE);
7119 accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
7120 binfo, t, list);
7121
7122 /* Add the vtables for each of our virtual bases using the vbase in T
7123 binfo. */
7124 for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
7125 vbase;
7126 vbase = TREE_CHAIN (vbase))
7127 {
7128 tree b;
7129
7130 if (!TREE_VIA_VIRTUAL (vbase))
7131 continue ;
7132 b = copied_binfo (vbase, binfo);
7133
7134 accumulate_vtbl_inits (b, vbase, binfo, t, list);
7135 }
7136 inits = TREE_VALUE (list);
7137
7138 /* Figure out the type of the construction vtable. */
7139 type = build_index_type (size_int (list_length (inits) - 1));
7140 type = build_cplus_array_type (vtable_entry_type, type);
7141 TREE_TYPE (vtbl) = type;
7142
7143 /* Initialize the construction vtable. */
7144 CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
7145 initialize_array (vtbl, inits);
7146 dump_vtable (t, binfo, vtbl);
7147 }
在上面的 7109 行 , mangle_ctor_vtbl_for_type 返回用于链接目的的 vtable 修饰名。接着的断言确保只有基类才会进入这个函数。然后一个新构建的 vtable 对象被封装入一个 tree_list 节点,并在 7119 行作为最后的参数传给下面的函数。注意 rtti_binfo 是合资格直接基类的 binfo ,该函数将为这个基类准备初始值。
这里, accumulate_vtbl_inits 按前序的次序处理感兴趣的基类及它的非虚拟基类,然后在 build_ctor_vblt_group 中,以在派生树中出现的次序,调用该函数处理基类的虚拟基类。出于方便,我们在下面重新显示相关的函数。
7159 static void
7160 accumulate_vtbl_inits (tree binfo, in class.c
7161 tree orig_binfo,
7162 tree rtti_binfo,
7163 tree t,
7164 tree inits)
7165 {
7166 int i;
7167 int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
7168
7169 my_friendly_assert (same_type_p (BINFO_TYPE (binfo),
7170 BINFO_TYPE (orig_binfo)),
7171 20000517);
7172
7173 /* If it doesn't have a vptr, we don't do anything. */
7174 if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
7175 return ;
7176
7177 /* If we're building a construction vtable, we're not interested in
7178 subobjects that don't require construction vtables. */
7179 if (ctor_vtbl_p
7180 && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
7181 && !binfo_via_virtual (orig_binfo, BINFO_TYPE (rtti_binfo)))
7182 return ;
7183
7184 /* Build the initializers for the BINFO-in-T vtable. */
7185 TREE_VALUE (inits)
7186 = chainon (TREE_VALUE (inits),
7187 dfs_accumulate_vtbl_inits (binfo, orig_binfo,
7188 rtti_binfo, t, inits));
7189
7190 /* Walk the BINFO and its bases. We walk in preorder so that as we
7191 initialize each vtable we can figure out at what offset the
7192 secondary vtable lies from the primary vtable. We can't use
7193 dfs_walk here because we need to iterate through bases of BINFO
7194 and RTTI_BINFO simultaneously. */
7195 for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
7196 {
7197 tree base_binfo = BINFO_BASETYPE (binfo, i);
7198
7199 /* Skip virtual bases. */
7200 if (TREE_VIA_VIRTUAL (base_binfo))
7201 continue ;
7202 accumulate_vtbl_inits (base_binfo,
7203 BINFO_BASETYPE (orig_binfo, i),
7204 rtti_binfo, t,
7205 inits);
7206 }
7207 }
这一次 , 上面 7167 行的 ctor_vtbl_p 是 true , 因为参数 t 总是指向最后派生类 , 而 rtti_binfo 总是其基类。 7179 行的条件滤除不从虚拟基类派生的非虚拟基类。
7212 static tree
7213 dfs_accumulate_vtbl_inits (tree binfo, in class.c
7214 tree orig_binfo,
7215 tree rtti_binfo,
7216 tree t,
7217 tree l)
7218 {
7219 tree inits = NULL_TREE;
7220 tree vtbl = NULL_TREE;
7221 int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
7222
7223 if (ctor_vtbl_p
7224 && TREE_VIA_VIRTUAL (orig_binfo) && BINFO_PRIMARY_P (orig_binfo))
7225 {
7226 /* In the hierarchy of BINFO_TYPE (RTTI_BINFO), this is a
7227 primary virtual base. If it is not the same primary in
7228 the hierarchy of T, we'll need to generate a ctor vtable
7229 for it, to place at its location in T. If it is the same
7230 primary, we still need a VTT entry for the vtable, but it
7231 should point to the ctor vtable for the base it is a
7232 primary for within the sub-hierarchy of RTTI_BINFO.
7233
7234 There are three possible cases:
7235
7236 1) We are in the same place.
7237 2) We are a primary base within a lost primary virtual base of
7238 RTTI_BINFO.
7239 3) We are primary to something not a base of RTTI_BINFO. */
7240
7241 tree b = BINFO_PRIMARY_BASE_OF (binfo);
7242 tree last = NULL_TREE;
7243
7244 /* First, look through the bases we are primary to for RTTI_BINFO
7245 or a virtual base. */
7246 for (; b; b = BINFO_PRIMARY_BASE_OF (b))
7247 {
7248 last = b;
7249 if (TREE_VIA_VIRTUAL (b) || b == rtti_binfo)
7250 break ;
7251 }
7252 /* If we run out of primary links, keep looking down our
7253 inheritance chain; we might be an indirect primary. */
7254 if (b == NULL_TREE)
7255 for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b))
7256 if (TREE_VIA_VIRTUAL (b) || b == rtti_binfo)
7257 break ;
7258
7259 /* If we found RTTI_BINFO, this is case 1. If we found a virtual
7260 base B and it is a base of RTTI_BINFO, this is case 2. In
7261 either case, we share our vtable with LAST, i.e. the
7262 derived-most base within B of which we are a primary. */
7263 if (b == rtti_binfo
7264 || (b && purpose_member (BINFO_TYPE (b),
7265 CLASSTYPE_VBASECLASSES (BINFO_TYPE (rtti_binfo)))))
7266 /* Just set our BINFO_VTABLE to point to LAST, as we may not have
7267 set LAST's BINFO_VTABLE yet. We'll extract the actual vptr in
7268 binfo_ctor_vtable after everything's been set up. */
7269 vtbl = last;
7270
7271 /* Otherwise, this is case 3 and we get our own. */
7272 }
7273 else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo))
7274 return inits;
7275
7276 if (!vtbl)
7277 {
7278 tree index;
7279 int non_fn_entries;
7280
7281 /* Compute the initializer for this vtable. */
7282 inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
7283 &non_fn_entries);
7284
7285 /* Figure out the position to which the VPTR should point. */
7286 vtbl = TREE_PURPOSE (l);
7287 vtbl = build1 (ADDR_EXPR,
7288 vtbl_ptr_type_node,
7289 vtbl);
7290 TREE_CONSTANT (vtbl) = 1;
7291 index = size_binop (PLUS_EXPR,
7292 size_int (non_fn_entries),
7293 size_int (list_length (TREE_VALUE (l))));
7294 index = size_binop (MULT_EXPR,
7295 TYPE_SIZE_UNIT (vtable_entry_type),
7296 index);
7297 vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
7298 TREE_CONSTANT (vtbl) = 1;
7299 }
7300
7301 if (ctor_vtbl_p)
7302 /* For a construction vtable, we can't overwrite BINFO_VTABLE.
7303 So, we make a TREE_LIST. Later, dfs_fixup_binfo_vtbls will
7304 straighten this out. */
7305 BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
7306 else if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))
7307 inits = NULL_TREE;
7308 else
7309 /* For an ordinary vtable, set BINFO_VTABLE. */
7310 BINFO_VTABLE (binfo) = vtbl;
7311
7312 return inits;
7313 }
参数 orig_binfo 应该总是指向感兴趣基类类型的 binfo 。而在 7273 行的断言 BINFO_NEW_VTABLE_MARKED 返回 true ,如果类型有属于自己的 vtable 。现在 rtti_binfo 是感兴趣直接基类的 binfo 。在我们的例子里,当处理 C 时, B1 , B2 就是这样的基类。而 t 指向最后派生类的 binfo ,在我们的例子中,它是类 C 。另外 binfo 是正在处理的基类的 binfo 。
这里当 accumulate_vtbl_inits 处理 B1 时,在 dfs_accumulate_vtbl_inits 的 7224 行条件, TREE_VIA_VIRTUAL 及 BINFO_PRIMARY_P 对于 orig_binfo 都是不成立的(这里是 B1 的 binfo );而在 7273 行的条件, orig_binfo 显然具有自己的 vtable ,该条件亦不成立。因此将进入 7276 行的 IF 块,这里面的处理在前一节已经看过,大同小异。因为 ctor_vtbl_p 是 true ,因而 7305 行得到执行,注意 binfo 是 B1-in-C 的 binfo ,它的 BINFO_VTABLE 是 NULL 。因为这里得到的 vtable 是构造( construction ) vtable ,它只能暂时借用 BINFO_VTABLE ,所以把它构建入一个 tree_list 。为之配合的函数有: binfo_ctor_vtable , dfs_fixup_binfo_vtbls 。
在 7119 行,当从 accumulate_vtbl_inits 退出时,例 1 的 B1-in-C 应该在其构造( construction ) vtable 里,具有如下的项(保存在 build_ctor_vtbl_group 中 7118 行的 list 的 TREE_PURPOSE 域,及 BINFO_VTABLE (B1-in-C 的 binfo) )。
Construction vtable for B1 (0xb7f2d980 instance) in C
C::_ZTC1C0_2B1: 6u entries
0 0u
4 0u
8 (int (*)(...))0
12 (int (*)(...))(& _ZTI2B1)
16 B1::_ZTcv0_n12_v0_n16_N2B11fEv // slot of B1::A::f
20 B1::f // slot of B1::f
接着在 7134 行对 accumulate_vtbl_inits 的调用中, binfo 是 C::B1 的 binfo ,而 7124 行获得了类型 B1 的 binfo ,因此 vbase 是 B1::A 的 binfo ,而 b 是 C::B1::A 的 binfo ,而 t 仍然是类型 C 。它们被传递给 dfs_accumulate_vtbl_inits ,按如下的映射关系: binfo ( b ), orig_binfo ( vbase ), rtti_binfo ( binfo )及 t ( t )。
那么 7223 行条件满足。在 7241 行, b 是 C::B1 的 binfo ;而 last 在 7248 行得到 C::B1 的 binfo 。结果 vtbl 在 7269 行被设置为 C::B1 的 binfo 。最后,在 7305 行, BINFO_VTABLE (C::B1::A 的 binfo) 被加入一个包含 C::B1 的 binfo 的 tree_list 节点。并且为 NULL 的 inits 被返回。
不过对于 B2-in-C ,事情稍有不同。同样在 7119 行退出 accumulate_vtbl_inits 时,例 1 中的 B2-in-C 应该在其构造( construction ) vtable 里,具有如下的项(保存在 build_ctor_vtbl_group 中 7118 行的 list 的 TREE_PURPOSE 域)。
Construction vtable for B2 (0xb7f2da00 instance) in C
C::_ZTC1C4_2B2: 10u entries
0 -4u
4 0u
8 (int (*)(...))0
12 (int (*)(...))(& _ZTI2B2)
16 B2::_ZTcv0_n12_v0_n16_N2B21fEv
20 B2::f // slot of B2::f
但在为 B2::A 调用的 dfs_accumulate_vtbl_inits 中, binfo : C::B2 的 binfo (参数: rtti_binfo ), vbase : B2::A 的 binfo (参数: orig_binfo ), b : C::B2::A 的 binfo (参数: binfo ), t : C (参数: t )。
那么在 7241 行, b 这次是 C::B2 的 binfo ;而在 7248 行的 last 得到 NULL ,因为它沿着路径 A à B1 à C 攀升。因此在 7276 行的条件中, vtbl 保持为 NULL 。因而为 B2::A 产生的构造( construction ) vtable 具有如下的项:
24 4u // part of A in B2 - begin
28 (int (*)(...))4
32 (int (*)(...))(& _ZTI2B2)
36 B2::_ZTcv0_n12_v0_n16_N2B21fEv // part of A in B2 - end
在 build_ctor_vtbl_group 的 7140 行为这些构造( construction ) vtable 重新构建了数组类型。接着在 7144 行,这个用于基类构造的 vtable 串接入最后派生类的 CLASSTYPE_VTABLES 。而在 7145 行的 initialize_array 为 vtable 项确切的类型准备初始值。
从 build_ctor_vtbl_group 回到 build_vtt_inits 时, 6916 行的 binfo_ctor_vtable 从 C::B1 得到 C::B1 的构造( construction ) vtable ( index 为 1 )。
6927 行的 FOR 循环对于 B1 或 B2 不做任何事,那么我们来到下面的代码。
build_vtt_inits (continue)
6935 /* Add secondary virtual pointers for all subobjects of BINFO with
6936 either virtual bases or reachable along a virtual path, except
6937 subobjects that are non-virtual primary bases. */
6938 secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
6939 TREE_TYPE (secondary_vptrs) = *index;
6940 VTT_TOP_LEVEL_P (secondary_vptrs) = top_level_p;
6941 VTT_MARKED_BINFO_P (secondary_vptrs) = 0;
6942
6943 dfs_walk_real (binfo,
6944 dfs_build_secondary_vptr_vtt_inits ,
6945 NULL,
6946 dfs_ctor_vtable_bases_queue_p,
6947 secondary_vptrs);
6948 VTT_MARKED_BINFO_P (secondary_vptrs) = 1;
6949 dfs_walk (binfo, dfs_unmark, dfs_ctor_vtable_bases_queue_p,
6950 secondary_vptrs);
6951
6952 *index = TREE_TYPE (secondary_vptrs);
6953
6954 /* The secondary vptrs come back in reverse order. After we reverse
6955 them, and add the INITS, the last init will be the first element
6956 of the chain. */
6957 secondary_vptrs = TREE_VALUE (secondary_vptrs);
6958 if (secondary_vptrs)
6959 {
6960 *inits = nreverse (secondary_vptrs);
6961 inits = &TREE_CHAIN (secondary_vptrs);
6962 my_friendly_assert (*inits == NULL_TREE, 20000517);
6963 }
6964
6965 /* Add the secondary VTTs for virtual bases. */
6966 if (top_level_p)
6967 for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
6968 {
6969 if (!TREE_VIA_VIRTUAL (b))
6970 continue ;
6971
6972 inits = build_vtt_inits (b, t, inits, index);
6973 }
6974
6975 if (!top_level_p)
6976 {
6977 tree data = tree_cons (t, binfo, NULL_TREE);
6978 VTT_TOP_LEVEL_P (data) = 0;
6979 VTT_MARKED_BINFO_P (data) = 0;
6980
6981 dfs_walk (binfo, dfs_fixup_binfo_vtbls ,
6982 dfs_ctor_vtable_bases_queue_p,
6983 data);
6984 }
6985
6986 return inits;
6987 }
上面的 secondary_vptrs 正如其名字所表示的,是在最后派生类的 VTT 中指向次要 vtable 的指针;而 index 指出这个指针所在的 VTT 的项。在 6943 行的遍历从 binfo 所指定的基类 binfo 开始(这里,即是 C::B1 的 binfo 或 C::B2 的 binfo ),并步入这个节点。下面的函数则以前序的次序处理访问的节点,看到参数 data 是 secondary_vptrs 。
6996 static tree
6997 dfs_build_secondary_vptr_vtt_inits (tree binfo, void* data) in class.c
6998 {
6999 tree l;
7000 tree t;
7001 tree init;
7002 tree index;
7003 int top_level_p;
7004
7005 l = (tree) data;
7006 t = TREE_CHAIN (l);
7007 top_level_p = VTT_TOP_LEVEL_P (l);
7008
7009 BINFO_MARKED (binfo) = 1;
7010
7011 /* We don't care about bases that don't have vtables. */
7012 if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
7013 return NULL_TREE;
7014
7015 /* We're only interested in proper subobjects of T. */
7016 if (same_type_p (BINFO_TYPE (binfo), t))
7017 return NULL_TREE;
7018
7019 /* We're not interested in non-virtual primary bases. */
7020 if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_P (binfo))
7021 return NULL_TREE;
7022
7023 /* If BINFO has virtual bases or is reachable via a virtual path
7024 from T, it'll have a secondary vptr. */
7025 if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
7026 && !binfo_via_virtual (binfo, t))
7027 return NULL_TREE;
7028
7029 /* Record the index where this secondary vptr can be found. */
7030 index = TREE_TYPE (l);
7031 if (top_level_p)
7032 {
7033 my_friendly_assert (!BINFO_VPTR_INDEX (binfo), 20010129);
7034 BINFO_VPTR_INDEX (binfo) = index;
7035 }
7036 TREE_TYPE (l) = size_binop (PLUS_EXPR, index,
7037 TYPE_SIZE_UNIT (ptr_type_node));
7038
7039 /* Add the initializer for the secondary vptr itself. */
7040 if (top_level_p && TREE_VIA_VIRTUAL (binfo))
7041 {
7042 /* It's a primary virtual base, and this is not the construction
7043 vtable. Find the base this is primary of in the inheritance graph,
7044 and use that base's vtable now. */
7045 while (BINFO_PRIMARY_BASE_OF (binfo))
7046 binfo = BINFO_PRIMARY_BASE_OF (binfo);
7047 }
7048 init = binfo_ctor_vtable (binfo);
7049 TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
7050
7051 return NULL_TREE;
7052 }
当遍历以 C::B1 的 binfo 为根的子树时,上面的 top_level_p 是 false , 7006 行的 t 是类型 B1 。这个节点被跳过,因为满足 7016 行的条件;在访问 C::B1::A 的 binfo 时,在 7048 行,因为 C::B1::A 的 binfo 的 BINFO_VTABLE 中保存的是 C::B1 的 binfo , binfo_ctor_vtable 辗转地再一次获得了 C::B1 的构造( construction ) vtable (保存在 index 为 2 的位置)。注意到这个函数总是返回 NULL ,它将强制进行整棵子树的遍历。
记得在 dfs_accumulate_vtbl_inits 的 7305 行,构造( construction ) vtable 暂时栖身在 BINFO_VTABLE 中。现在构造( construction ) vtable 已经记录在 VTT 中,不再需要在 BINFO_VTABLE 里混了。现在要通过尝试把 BINFO_VTABLE 恢复过来。注意其参数 data 的构成,在我们这里,上面由 C::B1::A 暂存的节点被移走了(对 C::B2 则是 C::B2::A )。
7075 static tree
7076 dfs_fixup_binfo_vtbls (tree binfo, void* data) in class.c
7077 {
7078 BINFO_MARKED (binfo) = 0;
7079
7080 /* We don't care about bases that don't have vtables. */
7081 if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
7082 return NULL_TREE;
7083
7084 /* If we scribbled the construction vtable vptr into BINFO, clear it
7085 out now. */
7086 if (BINFO_VTABLE (binfo)
7087 && TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
7088 && (TREE_PURPOSE (BINFO_VTABLE (binfo))
7089 == TREE_VALUE ((tree) data)))
7090 BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
7091
7092 return NULL_TREE;
7093 }
回过去看上面提到的 C::B2 的处理,在其 build_ctor_vtbl_group 返回到 build_vtt_inits 时,其构造( construction ) vtable 被保存在 VTT 中 index 为 3 的地方。而在其后对 C::B2 的 dfs_build_secondary_vptr_vtt_inits 的调用中,在 7048 行, binfo_ctor_vtable 得到了 B2::A 的构造( construction ) vtable ( index 为 4 )。
当完成了 B1 及 B2 的处理后,在 build_vtt_inits 的 6938 行,继续处理 C 。在 6943 行,开始遍历以 C 为根节点的派生树。那么在 dfs_build_secondary_vptr_vtt_inits 中, top_level_p 是 true , t 是最后派生类 C 。在这个前序遍历中, C 满足 7016 行条件, C::B1 满足 7020 行条件,退出该函数。对于 C::B2 , VTT 的索引 5 被置为 C::B2 的 vptr ,而其 vtable (这是个次要 vtable )的初始值则是上一节中得到的 BINFO_VTABLE(C::B2) ;同样对于 C::B1::A ,它的 vptr 在 VTT 索引为 6 的地方,其 vtable (也是次要 vtable )的初始值也是前一节中保存在 BINFO_VTABLE(A-in-C) 的内容。 C::B2::A 跳过,因为 A 已经在 C::B1::A 中访问了。
在 build_vtt_inits 的 6972 行,最后处理 A ,不过因为 A 不包含虚拟基类, build_vtt_inits 对它不做处理。
回到 build_vtt ,如果处理成功, inits 不为 NULL 。接下来就是为 VTT 构建正确的类型,及 VTT 类型的静态成员对象,并且把这个 VTT 对象置入最后派生类 CLASSTYPE_VTABLES 的链头。