为什么添加虚函数D
需要额外的
vptr
?类图像将以B
or开头C
,并且
D
可以将其功能附加到任何一个。(一旦你有了虚继承,你就需要某种指针,即使没有虚函数。)
添加一个虚函数A
会产生影响(几乎可以肯定,当然,这里的一切都取决于实现)。对于它的价值,您可能想尝试以下方法:
#include <iostream>
#include <iomanip>
#include <cstdint>
typedef std::uintptr_t Word;
class SaveIOFormat
{
std::basic_ios<char>* myStream;
char myFill;
std::basic_ios<char>::fmtflags myFlags;
int myPrecision;
public:
SaveIOFormat( std::basic_ios<char>& stream )
: myStream( &stream )
, myFill( stream.fill() )
, myFlags( stream.flags() )
, myPrecision( stream.precision() )
{
}
~SaveIOFormat()
{
myStream->fill( myFill );
myStream->flags( myFlags );
myStream->precision( myPrecision );
}
};
template <typename T>
class DumpAsWords
{
Word const* myObj;
typedef Word const* Iterator;
typedef char sizeMustBeMultipleOfSizeofWord
[ sizeof(T) % sizeof(uintptr_t) == 0 ? 1 : -1 ];
static int const ourLength = sizeof(T) / sizeof(Word);
public:
DumpAsWords( T const& obj )
: myObj( reinterpret_cast<Word const*>( &obj ) )
{
}
friend std::ostream& operator<<( std::ostream& dest,
DumpAsWords const& obj )
{
SaveIOFormat saveExcursion( dest );
dest.fill( '0' );
dest.setf( std::ios::hex, std::ios::basefield );
for ( Iterator current = obj.myObj, end = obj.myObj + ourLength;
current != end;
++ current ) {
if ( current != obj.myObj ) {
dest << ' ';
}
dest << std::setw( sizeof(Word) * 2 ) << *current;
}
return dest;
}
};
template <typename T>
DumpAsWords<T>
dump( T const& obj )
{
return DumpAsWords<T>( obj );
}
class B
{
Word i;
public:
B() : i( 1 ) {}
virtual ~B() {}
};
class L : virtual public B
{
Word i;
public:
L() : i( 2 ) {}
};
class R : virtual public B
{
Word i;
public:
R() : i( 3 ) {}
};
class D : public L, public R
{
Word i;
public:
D() : i( 4 ) {}
};
int
main()
{
D aD;
std::cout << "sizeof B: " << sizeof(B) << std::endl;
std::cout << "sizeof L: " << sizeof(L) << std::endl;
std::cout << "sizeof R: " << sizeof(R) << std::endl;
std::cout << "sizeof D: " << sizeof(D) << std::endl;
std::cout << std::endl;
std::cout << "addrof B: " << static_cast<B*>( &aD ) << std::endl;
std::cout << "addrof L: " << static_cast<L*>( &aD ) << std::endl;
std::cout << "addrof R: " << static_cast<R*>( &aD ) << std::endl;
std::cout << "addrof D: " << static_cast<D*>( &aD ) << std::endl;
std::cout << std::endl;
std::cout << "dump: " << dump( aD ) << std::endl;
return 0;
}
(如果它有点长,那是因为我从我的库中复制/粘贴了一些代码以使其更简单和更清晰。)
在我的机器上,这给出了:
sizeof B: 16
sizeof L: 32
sizeof R: 32
sizeof D: 56
addrof B: 00000000001AFEB8
addrof L: 00000000001AFE90
addrof R: 00000000001AFEA0
addrof D: 00000000001AFE90
dump: 000000013fb90bb0 0000000000000002 000000013fb90bb8 0000000000000003 0000000000000004 000000013fb90ba8 0000000000000001
如您所见,顺序是 D 中的 L,D 中的 R,D,B(在 L,R 和 D 中)。D 与 L 共享 vptr。
(这是在 64 位 Windows 机器上使用 VC++ 11 编译的。你的结果很容易不同。)