假设我们有以下两个类定义。
#include <iostream>
#include <array>
class A
{
public:
virtual void f() = 0;
};
class B : public A
{
public:
virtual void f() { std::cout << i << std::endl; }
int i;
};
此处sizeof(B) == 8
,可能是4个虚拟指针,4个是int
。
现在我们假设我们制作一个B数组,如下所示:
std::array<B, 10> x;
现在我们得到sizeof(x) == 80
。
如果我的理解是正确的,那么x
元素的所有方法调用都会被静态解析,因为我们知道编译时的类型。除非我们执行A* p = &x[i]
之类的操作,否则我甚至不需要存储虚拟指针。
如果你知道它不会被使用,有没有办法在没有虚拟指针的情况下创建B类型的对象?
即。模板类型nonvirtual<T>
,它不包含虚拟指针,并且不能被T的子类型指向?
答案 0 :(得分:2)
如果你知道它不会被使用,有没有办法在没有虚拟指针的情况下创建B类型的对象?
没有。物体就是它们。虚拟对象总是虚拟的。
毕竟,你可以这样做:
A *a = &x[2];
a->f();
这是完全合法和合法的代码。而且C ++必须允许它。类型B
是虚拟的,并且具有一定的大小。根据使用的位置,您不能将类型设置为不同的类型。
答案 1 :(得分:2)
在这里回答我自己的问题,但我发现以下工作是通过将A分成虚拟和非虚拟组件来完成的:
enum is_virtual
{
VIRTUAL,
STATIC
};
template <is_virtual X>
class A;
template<>
class A<STATIC>
{
};
template<>
class A<VIRTUAL> : public A<STATIC>
{
public:
virtual void f() = 0;
virtual ~A() {}
};
template <is_virtual X>
class B : public A<X>
{
public:
void f() { std::cout << i << std::endl; }
int i;
};
重要的是,在B<>
中不要将f()
指定为虚拟。这样,如果类继承A<VIRTUAL>
,它将是虚拟的,但如果它继承A<STATIC>
则不是虚拟的。然后我们可以做到以下几点:
int main()
{
std::cout << sizeof(B<STATIC>) << std::endl; // 4
std::cout << sizeof(B<VIRTUAL>) << std::endl; // 8
std::array<B<STATIC>, 10> x1;
std::array<B<VIRTUAL>, 10> x2;
std::cout << sizeof(x1) << std::endl; // 40
std::cout << sizeof(x2) << std::endl; // 80
}
答案 2 :(得分:0)
这将是一个很好的,但我想不出任何方法来撤销虚拟成员或避免存储虚拟指针。
你可以通过保持一个没有虚拟指针的大小为B的缓冲区来做一些讨厌的黑客攻击,然后使用强制转换等等。但是所有未定义的行为和平台相关。
答案 3 :(得分:0)
不幸的是,它不会在任何正常意义上工作,因为方法调用中的代码需要虚拟指针位于类定义中。
我想你可以将所有A和B的代码复制/粘贴到一个新类中,但这很快就会成为一个维护问题。