虚拟函数在哪里使用vpointer到vtables来解决方法调用,非虚拟方法在哪里存储以及如何解决?

时间:2019-07-20 04:34:08

标签: c++ methods vtable

具有定义的类

class A
{
    void AFunc1(){}
    void AFunc2(){}
    void AFunc3(){}
    virtual void AVirtualFunc1(){}
};

由于隐藏的sizeof()成员指向共享的vpointer,而该vtable的指针指向方法,因此其class B { void BFunc1(){} void BFunc2(){} void BFunc3(){} }; 的值将为4个字节。

但是,该类的实例

sizeof()

将仅具有1个字节的vpointer值,因为不需要vtable,并且也没有BFunc1()。如果是这样,函数BFunc2()BFunc3()<template> <div class="container"> <div class="row "> <div class="col-md-4"> <div class="filter"> <label><input type="checkbox" v-model="selectedCategory" value="0" /> All</label> <label><input type="checkbox" v-model="selectedCategory" value="1" /> Tech</label> <label><input type="checkbox" v-model="selectedCategory" value="2" /> Entertainment</label> <label><input type="checkbox" v-model="selectedCategory" value="3" /> Fictional</label> </div> </div> </div> <div class="col-md-8"> <div class="card" v-for="product in filteredProduct"> <div class="card-header">{{product. name}}</div> <div class="card-body"> <img :src="product.image"> <p>{{product.price}}</p> <p>{{product.category_id}}</p> </div> </div> </div> </div> </div> </template> <script> export default { data:function(){ return { products:[], selectedCategory: ["0"], } }, computed: { filteredProduct: function() { var app = this; var category = app.selectedCategory; console.log(category) if(category.includes("0")) { return app.products; } else { return app.products.filter(function(p) { return category.includes(p.category_id); }); } } }, mounted() { console.log('Product mounted.') var app = this; axios.get('/products') .then(function (resp) { app.products = resp.data; }) .catch(function (resp) { console.log(resp); alert("Could not load"); }); } } </script> 的存储位置以及对象实例如何引用它们?

1 个答案:

答案 0 :(得分:3)

对于实际上在某个地方使用的每个非虚函数,该函数的代码都会发送到目标文件,如果代码来自包含的标头并且在多个转换单元中使用,则可能会在多个文件中发出。另外,符号也插入到目标文件中。如果您是这样的Linux用户,则可以使用nm来查看已定义方法/功能/ ...的表:

  

nm main.o | c ++ filt

                    U __cxa_atexit
                    U __dso_handle
0000000000000062 t _GLOBAL__sub_I_main
0000000000000000 T main
0000000000000024 t __static_initialization_and_destruction_0(int, int)
0000000000000000 W A::AVirtualFunc1()
0000000000000000 W A::AFunc1()
0000000000000000 r __gnu_cxx::__default_lock_policy
                    U std::ios_base::Init::Init()
                    U std::ios_base::Init::~Init()
0000000000000000 b std::__ioinit
0000000000000000 V typeinfo for A
0000000000000000 V typeinfo name for A
0000000000000000 V vtable for A
                    U vtable for __cxxabiv1::__class_type_info

如您所见,A::AFunc1()被定义为weak符号。它的定义很弱,因为我们可以在不同的翻译单元中拥有多个实例,但是我们知道,它们都是相同的。 (就是这样,我们在C ++中有“一个定义规则”)。顺便说一句:如果您有多个使用相同标签的定义,则链接器仅放置一个,并且也没有错误消息。程序的行为由链接顺序定义。一件很糟糕的事!回到弱符号,如果我们多次将相同的方法存储在目标文件中,则链接器不应发出错误。现在,链接器可以简单地选择其中之一,而不会出现任何错误消息。例如,main函数在表中标记为“ T”。如果您多次用T标记相同的符号,则链接器将针对多个已定义函数发出错误消息。

您会看到目标文件中符号的地址为0000000。这意味着它当前没有地址。该地址将在静态可执行文件的链接时间内或程序启动时的动态链接时间内重定位。

您还可以看到,虚拟函数也以相同的方式存储,并且完全没有区别。也可以使用A::AVirtualFunc调用该方法本身,而无需跳过vtable。

您还将看到,vtable本身是目标文件的一部分,并标记为V。您还可以在多个目标文件中具有相同的vtable。链接器在最终链接中也只包含其中一个。