C++ GCC可以编译类作为结构使用吗?

C++ GCC可以编译类作为结构使用吗?,c++,class,struct,C++,Class,Struct,有没有办法强迫编译器(特别是GCC)将类编译成面向对象的C?具体来说,我想要实现的是写下以下内容: class Foo { public: float x, y, z; float bar(); int other(); ...etc }; Foo f; float result = f.bar() int obSize = sizeof(Foo); 但编译为与以下内容完全相同: Struct Foo { float x, y, z; }; float Foo_bar(Foo

有没有办法强迫编译器(特别是GCC)将类编译成面向对象的C?具体来说,我想要实现的是写下以下内容:

class Foo {
public:
  float x, y, z;
  float bar();
  int other();
  ...etc
};

Foo f;
float result = f.bar()
int obSize = sizeof(Foo);
但编译为与以下内容完全相同:

Struct Foo { float x, y, z; };
float Foo_bar(Foo *this);

Foo f;
float result = Foo_bar(&f);
int obSize = sizeof(Foo);
我的动机是增加可读性,但不会因为Foo的每个对象而受到内存损失。我想类实现通常是obSize

obSize = sizeof(float)*3 + sizeof(void*)*number_of_class_methods

主要是在内存受限的微控制器中使用C++类。然而,我想,如果我让它工作,我也会将它用于网络序列化(当然是在相同的endian机器上)。

您的编译器实际上正是为您这样做的。它甚至可以通过将
this
指针放在寄存器中而不是将其推到堆栈上(这至少是MSVC在Windows上所做的),来进行优化,而这是标准C调用约定无法做到的

至于:

obSize = sizeof(float)*3 + sizeof(void*)*number_of_class_methods
  • 这是完全错误的。你试过了吗
  • 即使您有虚拟函数,每个对象也只会添加一个指向函数表的指针(每个类一个表)。如果没有虚拟函数,则不会向对象中添加超出其成员的任何内容(也不会生成函数表)
  • void*
    表示指向数据的指针,而不是指向代码的指针(它们不需要具有相同的大小)
  • 不能保证等效C结构的大小是
    3*sizeof(float)

  • 您需要进行测试,但据我所知,如果所述方法是虚拟的,则类实例只存储指向其方法的指针;否则,一个结构和一个类将占用大致相同的内存量(除了由不同的编译器进行的不同对齐等)。

    实际上,我相信使用类不会带来特定的内存损失,因为类的每个实例都会存储一次成员函数。因此,您的内存占用更像
    1*sizeof(void*)*number\u\u\u class\u方法+N*sizeof(float)*3
    ,其中有
    N
    Foo
    实例


    只有在使用虚拟函数时,才会受到额外的惩罚。在这种情况下,每个对象都带有指向vtable的指针。

    不,你的想象是错误的。类方法在对象中完全不占用空间。为什么不编写一个类,并采用sizeof。然后再添加一些方法并再次打印sizeof。你会发现它没有改变。像这样的

    第一个节目

    class X
    {
    public:
      int y;
      void method1() {}
    };
    
    int main()
    {
      cout << sizeof(X) << '\n'; // prints 4
    }
    
    X类
    {
    公众:
    int-y;
    void method1(){}
    };
    int main()
    {
    
    coutC++已经为非多态类(没有虚拟方法的类)实现了您所说的功能

    一般来说,C++类将具有与C结构相同的大小,除非类包含一个或多个虚拟方法,在这种情况下,开销将是每个类实例的单个指针(通常称为VPTR)。 还有一个“vtbl”实例,每个虚拟函数都有一组指针,但该vtbl将在该类类型的所有对象之间共享(即,每个类类型有一个vtbl,该类对象的各种VPTR将指向同一个vtbl实例)

    <> P>总结,如果你的类没有虚拟方法,它将不大于相同的C结构。这符合C++哲学,不为你不使用的东西付费。 <>但是注意,C++类中的非静态成员函数确实需要在参数列表中没有明确提到的额外参数(<代码>这个<代码>指针),这实质上是您在问题中讨论的问题。

    脚注:在C++类和结构中,除了默认成员可访问性的微小差异外,在上面的回答中,当我使用“类”这个词时,行为也同样适用于C++中的结构。


    还要注意的是,如果您的类使用继承,那么继承的“开销”取决于继承的确切种类。但是,正如多态类和非多态类之间的区别一样,无论代价是什么,只有在您使用它时,它才会被引入。

    嗯,sizeof(class Foo)==sizeof(struct Foo)。struct X{}==X类{public:}根据定义。当然,除非使用了
    virtual
    关键字。请注意,请始终运行您发布的代码。感谢大家的教训。-1我很愚蠢…您键入了“sizeof(void)”…我想您的意思是“sizeof(void(*)())或类似的东西。为什么要否决?如果我的答案中有错误,请说什么。(我不是向下投票人)。
    void*
    和指向函数的指针不兼容,不需要相同的大小。此外,没有虚拟函数,也没有表。由于对齐的考虑,没有任何命令要求
    sizeof(Foo)==3*sizeof(
    float`).
    void*
    issue是个好消息。事实上,标准只规定变量将按照声明的顺序分配,而不是在数学上没有填充,因此
    sizeof(Foo)>=3*sizeof(float)
    另外,我确实提到vtable只在使用虚拟函数时才起作用。如果vtable的任何成员是虚拟的,它将只存储一个指向该vtable的指针,如果向其中添加函数,则只有vtable本身会增长。一个类的5M对象和5M虚拟函数不会占用100TB的内存。确切地说,如果其中任何一个成员是虚拟的,它将存储一个指针E方法是虚拟的。所以,添加一个类的方法会增加类的大小,这仍然不是真的。调用约定不在C++标准的范围内。但是,在X8664上,最多6个第一个参数在C寄存器中通过寄存器传递。@ Maxim:很好知道。但是,第一个参数是指针的事实。一个在函数调用中很可能被查找的类对于C编译器来说是未知的。无法理解你的最后一个句子。@ McXim: C++中的方法调用对第一个论证有特殊的意义。
    class X
    {
    public:
      int y;
      void method1() {}
      void method2() {}
      void method3() {}
      void method4() {}
      void method5() {}
      void method6() {}
    };
    
    int main()
    {
      cout << sizeof(X) << '\n'; // also prints 4
    }