C++类对象的内存结构

(C/C++必学)深入剖析类和其内存结构 一、前言 作为一个不断进步的程序员,在我们会使用一项技能后,不能只知其然不知其所以然,针对非科班或非系统成才的野生程序员,更应该在熟练使用后进行深入剖析和理解。要秉承看懂,会用,理解,复现的步骤进行学习,在使用这项技能后别人问到为什么要这么使用或者面试问到深层次的问题时不至于无所应对。有种“我知道怎么用,但是我不知道为什么”的无力感。 二、什么是类 1、类的组成 一个类由类名,类成员函数,类成员变量以及其他(静态变量,友元等)组成,以下面的 Demo ... 阅读详情

    本文全文转载于:https://blog.youkuaiyun.com/fenxinzi557/article/details/51995911

(1) 无虚函数继承

(2)有一个虚函数继承 

(3)全部虚函数都继承 

(4)多重继承 

(6)菱形继承

(7)单一虚继承

(8)菱形虚继承 (最重要)

 结论: 


    在VS中查看类对象的内存布局的方法:右击源文件——>属性——>C/C++——>命令行——>输入:

/d1 reportSingleClassLayoutXXX(其中XXX为类名)

1、C++类的存储 

    C++中最重要的就是类,那么一个类的对象,它在内存中如何存储的?它占内存中多少个字节? 首先确定类的构成。数据成员:可以是内置类型,类类型。 函数成员:虚函数,非虚函数 。

(1)数据成员 

    1)内置类型对齐原则,内置类型就是常用的:char,short,long,int,float,double. 这些内置类型在类的对象中对齐方式,字节为单位(在c 中结构体也是一样的) :char 1 、short 2 、long 4 、int 4 、float 4 、double 8 。
    2)类类型对齐原则(c 中就是结构体对齐原则) 取类中最长的数据成员作为对齐原则。例如,类中最长为 double,那么就是8 个字节。 

(2)函数成员 

    函数成员是不占用内存中类的对象的字节。为什么呢,你可以这样理解,c++中为了兼容c也允许struct 作为类的声明。在c 中struct 是用来声明结构体类型的,只不过c 中的结构体没有函数成员。 同样 c++中允许的函数成员,只不过是类给函数提供了一个作用域。 一个对象调用函数的时候,可以等价为普通函数的调用 。例如:

class A
{
    cout<<"Hello";
};
A a;
a.f();

    a.f()等价于调用f(&a);类中的成员函数(static 成员函数除外)形参中都有个隐含的this指针,它指向类对象本身。当对象 a 调用f()的时候,它会把a 的地址传给this 指针,所以f()就等价执行:

f(const A* this){
    cout<<"Hello";
}

    所以对象中并不需要保存函数成员。 

(3)类对象的字节数 

class A
{
    char c;
    int i;
};
A a;

    这对象a 的内存大小sizeof(a)=8(字节为单位) 。c 放在起始位置0,占1 个字节。 i 是int 要4 字节对齐,所以前面要空3 字节。它要从位置4 开始存储,占4,5,6,7 四 个位置。 最后类要按照他最长的数据成员对齐,就是i也就是4 字节对齐.因为已经占用了8 个字节, 8 是对齐4 的,所以不用额外增加字节数了。最后sizeof(a)=8。 

class B
{
    doube d;
    char c;
    A a; //1 中的类类型A
};
B b;

    这对象b的内存大小sizeof(b)=24(字节为单位) 。d 放在起始位置0到7,占8个字节。 c 是char要1字节对齐,所以放在位置8,占1 个字节。 a是类类型,在1 中可以知道它是8字节对齐的,所以前面要空7 个字节,它从位置16 开始存储,一直到23,占8个字节。 最后类要按照他最长的数据成员对齐,就是d也就是8字节对齐,因为已经占用了24 个字节,24是对齐8 的,所以不用额外增加字节数了。最后sizeof(b)=24。 

class c
{
    char c;
    int i1;
    double d;
    int i2;
};
C c;

    你知道sizeof(c)=多少吗? 答案:首先存储字符变量c,0位置存储,占1个字节;然后存储整型变量i1,4个字节对齐,因此从4~7位置存储,占4个字节;然后存储双精度变量d,从8~15位置存储,占8个字节;最后存储整型变量i2,从位置16~19存储占4个字节;最后对齐到最长的(8个字节),及补全20~23位置,整个占24个字节。 

(4)含有虚函数的类对象字节数

    我们在一开始的时候,就说了成员函数中有虚函数。c++为了处理多态,所以引入虚函数, 在一个类对象存储空间中,第一个位置需要4 个字节来存储一个指针。这个指针是指向该类的虚函数表的。也就是这个指针的值就是改类的虚函数表的地址。所以就比上面说的多了 4 个字节。 例如: 

class D 
{ 
public: 
    virtual void f(){}; 
    double d; 
} 
D d; 

    sizeof(d)=16,接下来看派生类对象的内存大小:

class E:D 
{
public:
    virtual void f(){};     
private: 
    int d0; 
    char c; 
    int d1; 
}; 
E e; 

    sizeof(e)=32; 基类中有虚函数,所以派生类对象一开始要 4 个字节存储指向虚函数表的指针。 然后继承 D 中的数据成员double d; 它要8 字节对齐,所以前面空4 个字节。 下面就开始存储 d0,c,d1.最后类对齐可计算得到32.

2、类对象内存结构 

    在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。 对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。 对于子类的子类,也是同样的原理。但是无论继承了多少个子类,对象中始终只有一个虚函数表指针。 

                                         

    为了探讨C++类对象的内存布局,先来写几个类和函数 。首先写一个基类: 

class Base 
{ 
public: 
    virtual void f() { cout << “Base::f” << endl; } 
    virtual void g() { cout << “Base::g” << endl; } 
    virtual void h() { cout << “Base::h” << endl; } 
    int base; 
protected: 
private: 
}; 

   这个基类的内存布局为:

1>  class Base	size(8):
1>  	+---
1>   0	| {vfptr}
1>   4	| base
1>  	+---
1>
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::f
1>   1	| &Base::g
1>   2	| &Base::h

 然后,我们多种不同的继承情况来研究子类的内存对象结构。 

(1) 无虚函数继承

//子类1,无虚函数重载 
class Child1 : public Base 
{ 
public: 
    virtual void f1() { cout << “Child1::f1” << endl; } 
    virtual void g1() { cout << “Child1::g1” << endl; } 
    virtual void h1() { cout << “Child1::h1” << endl; } 
    int child1; 
protected: 
private: 
}; 

    Child1的内存布局为:

1>  class Child1	size(12):
1>  	+---
1>  	| +--- (base class Base)
1>   0	| | {vfptr}
1>   4	| | base
1>  	| +---
1>   8	| child1
1>  	+---
1>
1>  Child1::$vftable@:
1>  	| &Child1_meta
1>  	|  0
1>   0	| &Base::f
1>   1	| &Base::g
1>   2	| &Base::h
1>   3	| &Child1::f1
1>   4	| &Child1::g1
1>   5	| &Child1::h1

 这个子类Child1没有继承任何一个基类的虚函数,因此它的虚函数表如下图: 
                                      
    我们可以看出,子类的虚函数表中,先存放基类的虚函数,在存放子类自己的虚函数。 

(2)有一个虚函数继承 

class Child2 : public Base 
{ 
public: 
    virtual void f() { cout << “Child2::f” << endl; } 
    virtual void g1() { cout << “Child2::g1” << endl; } 
    virtual void h1() { cout << “Child2::h1” << endl; } 
    int child2; 
protected: 
private: 
}; 
 

    Child2的内存布局为:

1>  class Child2	size(12):
1>  	+---
1>  	| +--- (base class Base)
1>   0	| | {vfptr}
1>   4	| | base
1>  	| +---
1>   8	| child2
1>  	+---
1>
1>  Child2::$vftable@:
1>  	| &Child2_meta
1>  	|  0
1>   0	| &Child2::f
1>   1	| &Base::g
1>   2	| &Base::h
1>   3	| &Child2::g1
1>   4	| &Child2::h1

 

                                           

    当子类重写了父类的虚函数,则编译器会将子类虚函数表中对应的父类的虚函数替换成子类的函数。 

(3)全部虚函数都继承 

//子类3,全部虚函数重载 
class Child3 : public Base 
{ 
public: 
    virtual void f() { cout << “Child3::f” << endl; } 
    virtual void g() { cout << “Child3::g” << endl; } 
    virtual void h() { cout << “Child3::h” << endl; } 
protected: 
    int x; 
private: 
}; 

    Child3的内存布局为:

1>  class Child3	size(12):
1>  	+---
1>  	| +--- (base class Base)
1>   0	| | {vfptr}
1>   4	| | base
1>  	| +---
1>   8	| child2
1>  	+---
1>
1>  Child3::$vftable@:
1>  	| &Child3_meta
1>  	|  0
1>   0	| &Child3::f
1>   1	| &Child3::g
1>   2	| &Child3::h

                                                 

(4)多重继承 

class Base3
{
public:
	virtual void f3() { cout << "Base3::f3" << endl; }
	virtual void g3() { cout << "Base3::g3" << endl; }
	virtual void h3() { cout << "Base3::h3" << endl; }
	int base3;
protected:
private:
};

class Base4
{
public:
	virtual void f4() { cout << "Base4::f4" << endl; }
	virtual void g4() { cout << "Base4::g4" << endl; }
	virtual void h4() { cout << "Base4::h4" << endl; }
	int base4;
protected:
private:
};

class Child5 : public Base3,public Base4
{
public:
	virtual void f3() { cout << "child5::f3" << endl; }
	virtual void f4() { cout << "Child5::f4" << endl; }
	virtual void f5() { cout << "Child5::f5" << endl; }
	virtual void g5() { cout << "Child5::g5" << endl; }
	virtual void h5() { cout << "Child5::h5" << endl; }
	int child5;
protected:
private:
};

Child5的内存布局为:

1>  class Child5	size(20):
1>  	+---
1>  	| +--- (base class Base3)
1>   0	| | {vfptr}
1>   4	| | base3
1>  	| +---
1>  	| +--- (base class Base4)
1>   8	| | {vfptr}
1>  12	| | base4
1>  	| +---
1>  16	| child5
1>  	+---
1>
1>  Child5::$vftable@Base3@:
1>  	| &Child5_meta
1>  	|  0
1>   0	| &Child5::f3
1>   1	| &Base3::g3
1>   2	| &Base3::h3
1>   3	| &Child5::f5
1>   4	| &Child5::g5
1>   5	| &Child5::h5
1>
1>  Child5::$vftable@Base4@:
1>  	| -8
1>   0	| &Child5::f4
1>   1	| &Base4::g4
1>   2	| &Base4::h4

    我们可以看到,当子类继承了多个父类,Child5将Base3作为主基类,也就是将它虚函数“并入"Base3的虚函数表之中,并将Base3的虚指针作为Child5的内存起始地址。那么子类的内存结构是这样的:

                                  

(6)菱形继承

class Base
{
public:
	virtual void f() { cout << "Base::f" << endl; }
	virtual void g() { cout << "Base::g" << endl; }
	virtual void h() { cout << "Base::h" << endl; }
	int base;
protected:
private:
};


class Base3:public Base
{
public:
	virtual void f3() { cout << "Base3::f3" << endl; }
	virtual void g3() { cout << "Base3::g3" << endl; }
	virtual void h3() { cout << "Base3::h3" << endl; }
	int base3;
protected:
private:
};

class Base4:public Base
{
public:
	virtual void f4() { cout << "Base4::f4" << endl; }
	virtual void g4() { cout << "Base4::g4" << endl; }
	virtual void h4() { cout << "Base4::h4" << endl; }
	int base4;
protected:
private:
};

class Child6 : public Base3,public Base4
{
public:
    virtual void f()  { cout << "child6::f" << endl; }
	virtual void f3() { cout << "child6::f3" << endl; }
	virtual void f4() { cout << "Child6::f4" << endl; }
	virtual void f6() { cout << "Child6::f6" << endl; }
	virtual void g6() { cout << "Child6::g6" << endl; }
	virtual void h6() { cout << "Child6::h6" << endl; }
	int child6;
protected:
private:
};

Child6的内存布局为:

1>  class Child6	size(28):
1>  	+---
1>  	| +--- (base class Base3)
1>  	| | +--- (base class Base)
1>   0	| | | {vfptr}
1>   4	| | | base
1>  	| | +---
1>   8	| | base3
1>  	| +---
1>  	| +--- (base class Base4)
1>  	| | +--- (base class Base)
1>  12	| | | {vfptr}
1>  16	| | | base
1>  	| | +---
1>  20	| | base4
1>  	| +---
1>  24	| child6
1>  	+---
1>
1>  Child6::$vftable@Base3@:
1>  	| &Child6_meta
1>  	|  0
1>   0	| &Child6::f
1>   1	| &Base::g
1>   2	| &Base::h
1>   3	| &Child6::f3
1>   4	| &Base3::g3
1>   5	| &Base3::h3
1>   6	| &Child6::f6
1>   7	| &Child6::g6
1>   8	| &Child6::h6
1>
1>  Child6::$vftable@Base4@:
1>  	| -12
1>   0	| &thunk: this-=12; goto Child6::f
1>   1	| &Base::g
1>   2	| &Base::h
1>   3	| &Child6::f4
1>   4	| &Base4::g4
1>   5	| &Base4::h4

    在菱形继承中,如果没有加上virtual关键字,那么子类会保存间接基类成员的两个备份。 此外,如果子类重写了间接基类的成员函数,那么将会重写第一个父类虚函数表中所继承的间接基类的虚函数,而第二个父类的虚函数表中所继承的间接基类的虚函数将会变成一个指针,指向第一个父类虚函数表中所继承的间接基类的虚函数。

                       

(7)单一虚继承

class Base
{
public:
	virtual void f() { cout << "Base::f" << endl; }
	virtual void g() { cout << "Base::g" << endl; }
	virtual void h() { cout << "Base::h" << endl; }
	int base;
protected:
private:
};


class Child : virtual public Base
{
public:
	virtual void f()  { cout << "Base::f" << endl; }
	virtual void f1() { cout << "Child::f1" << endl; }
	virtual void g1() { cout << "Child::g1" << endl; }
	virtual void h1() { cout << "Child::h1" << endl; }
	int child;
protected:
private:
};

Child的内存布局为:

1>  class Child	size(20):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>   8	| child
1>  	+---
1>  	+--- (virtual base Base)
1>  12	| {vfptr}
1>  16	| base
1>  	+---
1>
1>  Child::$vftable@Child@:
1>  	| &Child_meta
1>  	|  0
1>   0	| &Child::f1
1>   1	| &Child::g1
1>   2	| &Child::h1
1>
1>  Child::$vbtable@:
1>   0	| -4
1>   1	| 8 (Childd(Child+4)Base)
1>
1>  Child::$vftable@Base@:
1>  	| -12
1>   0	| &Child::f
1>   1	| &Base::g
1>   2	| &Base::h

    虚拟继承的子类的内存结构,和普通继承完全不同。虚拟继承的子类,有单独的虚函数表, 另外也单独保存一份父类的虚函数表,两部分之间用一个四个字节的0x00000000来作为分界。子类的内存中,首先是自己的虚函数表,然后是子类的数据成员,然后是0x0,之后就是父类的虚函数表,之后是父类的数据成员。 
    如果子类没有自己的虚函数,那么子类就不会有虚函数表,但是子类数据和父类数据之间,还是需要0x0来间隔。因此,在虚拟继承中,子类和父类的数据,是完全间隔的,先存放子类自己的虚函数表和数据,中间以0x分界,最后保存父类的虚函数和数据。如果子类重载了父类的虚函数,那么则将子类内存中父类虚函数表的相应函数替换。 

                                            

(8)菱形虚继承(最重要) 

class Base
{
public:
	virtual void f() { cout << "Base::f" << endl; }
	virtual void g() { cout << "Base::g" << endl; }
	virtual void h() { cout << "Base::h" << endl; }
	int base;
protected:
private:
};


class Base3 :virtual public Base
{
public:
    virtual void f3() { cout << "Base3::f3" << endl; }
	virtual void g3() { cout << "Base3::g3" << endl; }
	virtual void h3() { cout << "Base3::h3" << endl; }
	int base3;
protected:
private:
};

class Base4 :virtual public Base
{
public:
	virtual void f4() { cout << "Base4::f4" << endl; }
	virtual void g4() { cout << "Base4::g4" << endl; }
	virtual void h4() { cout << "Base4::h4" << endl; }
	int base4;
protected:
private:
};

class Child7 : public Base3, public Base4
{
public:
        virtual void f()  { cout << "child7::f" << endl; }
	virtual void f3() { cout << "child7::f3" << endl; }
	virtual void f4() { cout << "Child7::f4" << endl; }
	virtual void f7() { cout << "Child7::f7" << endl; }
	virtual void g7() { cout << "Child7::g7" << endl; }
	virtual void h7() { cout << "Child7::h7" << endl; }
	int child7;
protected:
private:
};

Child7的内存布局为:

1>  class Child7	size(36):
1>  	+---
1>  	| +--- (base class Base3)
1>   0	| | {vfptr}
1>   4	| | {vbptr}
1>   8	| | base3
1>  	| +---
1>  	| +--- (base class Base4)
1>  12	| | {vfptr}
1>  16	| | {vbptr}
1>  20	| | base4
1>  	| +---
1>  24	| child7
1>  	+---
1>  	+--- (virtual base Base)
1>  28	| {vfptr}
1>  32	| base
1>  	+---
1>
1>  Child7::$vftable@Base3@:
1>  	| &Child7_meta
1>  	|  0
1>   0	| &Child7::f3
1>   1	| &Base3::g3
1>   2	| &Base3::h3
1>   3	| &Child7::f7
1>   4	| &Child7::g7
1>   5	| &Child7::h7
1>
1>  Child7::$vftable@Base4@:
1>  	| -12
1>   0	| &Child7::f4
1>   1	| &Base4::g4
1>   2	| &Base4::h4
1>
1>  Child7::$vbtable@Base3@:
1>   0	| -4
1>   1	| 24 (Child7d(Base3+4)Base)
1>
1>  Child7::$vbtable@Base4@:
1>   0	| -4
1>   1	| 12 (Child7d(Base4+4)Base)
1>
1>  Child7::$vftable@Base@:
1>  	| -28
1>   0	| &Child7::f
1>   1	| &Base::g
1>   2	| &Base::h

    在Child7的内存布局中,先保存直接基类Base3的拷贝,由于Base3单一虚继承了Base,因此Base3中先存放自己的虚表指针和数据成员,中间有一个四字节分界,因此Base3的拷贝总共为12B。接着保存Base4的拷贝,Base4和Base3类似,也为12B。紧接着保存的是Child7的数据成员4B,然后保存简介基类Base的虚表指针和数据成员(8B)。总共加起来一共36B。Child7的虚函数放在多继承的第一个父类Base3的虚表中。可见,在菱形虚继承中,子类只保存间接基类的一个拷贝,就不存在重复保存间接基类多个拷贝的问题。 

               

   结论: 

(1)对于基类,如果有虚函数,那么先存放虚函数表指针,然后存放自己的数据成员;如果没有虚函数,那么直接存放数据成员。 

(2)对于单一继承的类对象,先存放父类的数据拷贝(包括虚函数表指针),然后是本类的数据。 

(3)虚函数表中,先存放父类的虚函数,再存放子类的虚函数 。

(4)如果重载了父类的某些虚函数,那么新的虚函数将虚函数表中父类的这些虚函数覆盖。 

(5)对于多重继承,先存放第一个父类的数据拷贝,在存放第二个父类的数据拷贝,一次类推,最后存放自己的数据成员。其中每一个父类拷贝都包含一个虚函数表指针。如果子类重载了某个父类的某个虚函数,那么该将该父类虚函数表的函数覆盖。另外,子类自己的虚函数,存储于第一个父类的虚函数表后边部分。 

(6)对于单一虚继承,会保存两个虚表指针。子类的内存中,首先是自己的虚函数表,然后是子类的数据成员,然后是0x0,之后就是父类的虚函数表,之后是父类的数据成员。如果子类重载了父类的虚函数,那么则将子类内存中父类虚函数表的相应函数替换。

(7) 对于菱形虚继承,会先保存第一个直接基类的拷贝,然后保存第二个直接基类的拷贝,然后保存子类的数据成员,最后才保存间接基类的虚表指针和数据成员。子类的虚函数保存在第一个直接基类的虚表中。

参考:https://blog.youkuaiyun.com/fenxinzi557/article/details/51995911 

c++类的内存结构(单继承) 关于c++类的内存的文章在网上有许多,但是,大多是一段段代码和说明,偶尔有图文并茂的,总觉不是很详细,没有一目了然之感觉 并且大部分也没有涉及虚析构,也没有说明访问标号的影响(虽然事实是没有影响)。而这块内容对于理解多态、重写、继承的构造和析构又是足够重要的。 终于下定决心,自己动手,在参考多方资料后,终有此文。 一、基类内存结构 1.1 不带虚函数、虚析构的基类: class Ba 阅读详情

相关推荐

c++派生类内存分布图

在这里主要看一下带有虚函数的派生类的内存分布图 1.单继承 class Base { private: int b; public: virtual void show1() { cout<<"Base::show1"<<endl; } virtual void show2() { cout<<"Base::show2"<<endl; } }; class Deriv

qq_36129744的博客 1072

【C++】c++内存结构

栈 stack :是那些编译器在需要时分配,在不需要时自动清除的存储区。存放在栈中的数据只在当前函数及下一层函数中有效,一旦函数返回了,这些数据也就自动释放了。在 C 语言中,未初始化的放在.bss段中,初始化的放在.data段中;堆 heap :由 new 分配的内存块,其释放编译器不去管,由程序员自己控制。代码区 (.text段) :存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。常量存储区 (.rodata段) :存放常量,不允许修改(通过非正当手段也可以修改)。

qingshanlvshui9的博客 579

交通小白首投TRB就中Oral?我的完整时间线与避坑指南(附Editorial Manager实操截图)

本文详细解析了交通领域新手如何高效完成TRB国际会议投稿的全流程,从选题策略到投稿系统实操,再到评审过程解析和常见误区避坑指南。特别针对初次投稿者提供了实用建议,包括时间规划、选题考量、Editorial Manager系统操作技巧,以及如何应对评审意见。文章还分享了从录用到会议参与的关键步骤,帮助研究者提升投稿成功率。

weixin_27303545的博客 387

【C++内存管理之一】内存结构简介

文章目录一、内存结构简介1、内存分配方式1、栈2、堆3、自由存储去4、全局区(静态区)5、常量区2、堆栈的区别1、举个栗子2、区别 一、内存结构简介 C++的内存结构,主要分为五个区域: 栈区、堆区、全局区(静态区)、常量区、代码区。 扩展链接 堆栈大小设置 1、内存分配方式 1、栈 1、由编译器和操作系统管理; 2、函数执行开始时,函数内的局部变量存储在栈中;函数执行结束时,这些存储单元自动被释...

Joker_N的博客 4506

在边缘部署实时视觉应用程序

克隆代码库后,压缩源文件夹的内容,并将生成的存档文件上传到上一节中创建的 S3 存储桶中。在本教程中,我们将使用 AWS Greengrass,因为它支持大多数 Windows 和 Linux 设备,包括我们的目标 Jetson AGX Xavier。此外,模型还可以量化到更低的精度,从而加快推理速度,但对于较大的模型,此过程通常较长(约 45 分钟)。本例中的脚本只是启动一个 Bash 环境,切换到解压后的构件目录,最后使用所需的命令行参数运行 Deepstream 应用。每个模型类型都有其独有的格式。

2501_91623519的博客 1294

Informer复现 -- 完整模型

有了数据和核心的ProbAttention,接下来就可以复现完整的Informer(图1)了。图1:Informer模型结构[1]如果对图1还不太熟悉的同学,可以参考图2。由图2可知,informer与Transformer之间的差异并不大。主要区别是ProbAttention和可能的encoder最后一层的conv(源代码中用来distil)。图2:参考Transformer画的Informer模型结构。

AI_daily的博客 3492

C++类的存储及类对象内存结构

本文分两部分,前半部分讲类的存储后半部分讲类的内存结构。 C++类的存储 c++中最重要的就是类,那么一个类的对象,它在内存中如何存储的?它占 内存中多少个字节? 首先确定类的构成: 1,数据成员:可以是内置类型,类类型。 2,函数成员:虚函数,非虚函数 1)数据成员 内置类型对齐原则 内置类型就是常用的:char,short,long,int,float,double. 这些内

fenxinzi557的博客 2万+

RC模型车多电机驱动方案:从电调PWM原理到四电机安全连接实战

在电机控制领域,PWM(脉冲宽度调制)是实现精确调速的核心技术。其原理是通过调节固定周期内高电平的脉宽来编码控制指令,进而驱动电子调速器(电调)改变输出功率。这项技术对于需要多电机协同工作的场景,如RC模型车的差速转向或重型负载驱动,具有关键价值。它能实现动力的精细分配与同步,提升车辆的可控性与通过性。在实际应用中,为确保系统稳定,必须关注电流分配与信号同步问题。例如,通过为每个电机配备独立电调并采用信号并联(Y线)的方式,可以构建可靠的四电机驱动系统。这种方案能有效避免因单个电调过载或电机反电动势不一致导

weixin_30664615的博客 382

C++类对象内存结构

首先介绍一下C++中有继承关系的类对象内存的布局:  在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。  对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。  对于子类的子类,也是同样的原理。但是无论继承了多少个子类,对象中始终只有一个虚函数

lxitong的专栏 520

扫地机器人视觉+IMU融合导航路径规划技术详解

本文介绍了基于视觉-惯性里程计(VIO)的扫地机器人自主导航系统。系统硬件由RGB摄像头、IMU传感器和编码器组成,软件架构采用分层设计,包括传感器数据采集层、数据融合层、SLAM定位层和路径规划层。核心技术包括:1)融合视觉特征提取(ORB算法)与IMU预积分的VIO;2)基于栅格地图的SLAM构建;3)结合A*全局规划和动态窗口法(DWA)局部避障的路径规划。文章提供了完整的Python实现代码,涵盖传感器数据融合、特征匹配和运动估计等关键功能模块。该系统实现了扫地机器人的精准定位和环境感知能力。

电脑管家 1463

从DIY到实战:手把手教你搭建一个媲美吉时利2450的nA级电流源表(附原理图与避坑指南)

本文详细解析如何从零打造nA级精密电流源,涵盖核心设计原理、PCB布局技巧、热电偶效应应对及校准验证体系。通过低成本替代方案和优化设计,实现媲美商用源表的性能,特别适合硬件爱好者和独立开发者。文章还提供原理图与避坑指南,助你轻松搭建高精度电流源系统。

weixin_42656416的博客 293

c++类对象内存结构

C++类对象内存结构   首先介绍一下C++中有继承关系的类对象内存的布局:  在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。  对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。  对于子类的子类,也是同样的原理。但是无论继承了多少

北方的雪之博客专栏 805

设计智能化的企业并购目标筛选多维度评估模型

企业并购是企业扩张和战略调整的重要手段,其目的在于实现资源的整合、优势互补和效率提升。评估指标单一:传统评估方法主要依赖财务指标,如净利润、市场份额等,忽视了企业其他重要的非财务指标,如品牌价值、客户满意度等。主观性较强:评估过程中,往往依赖于评估人员的经验和直觉,缺乏客观性,导致评估结果可能存在偏差。评估效率低:传统的评估方法通常需要大量的人力和时间,效率较低,难以应对大规模并购项目的需求。因此,设计一种智能化的企业并购目标筛选多维度评估模型,显得尤为必要。

SuperAGI2025 1034

C++类对象内存结构 .

class A { private: double a; public: A(int i) :a(i) {} virtual void print_A1() {  printf( "A::print_A1()!"); } virtual void print_A2() { printf("A::print_A2()!"); } }; class B { priva

发展是曲折的但也是前进的 778

海外购物商城源码 带即时通讯IM源码

在海外购物商城中,即时通讯IM源码可以为用户提供更便捷、高效的沟通方式,帮助解决跨国交易中的语言和文化差异问题。总之,即时通讯IM源码在海外购物商城中扮演着重要的角色,可以为用户提供更方便、高效的沟通方式,解决跨国交易中的语言和文化差异问题。(购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不要购买)实时翻译:即时通讯IM源码提供实时翻译功能,能够快速准确地翻译不同语言之间的文字、语音、视频等信息,帮助用户克服语言障碍。

很酷的站长的博客 259

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C++类对象内存结构(转)

C++类对象内存结构(转) 2010-12-20 17:41 http://hi.baidu.com/baifei_110/blog/item/7be35422fceb74439822ed13.html http://wenku.baidu.com/view/2c1229c55fbfc77da269b1fa.html 此日志的引用通告 URL 是

anhkgg的专栏 934

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++类对象的内存组织结构

<br />                                      C++类对象的内存组织结构: <br />      在面向对象语言C++中,每一个对象是内存中的一块内存空间,这块内存空间的的前四个字节是一个指向虚函数列表的指针(每个类中有且只有一个虚函数表,供所有对象共享,前一部分是基类的虚函数指针后面是子类新定义的虚函数指针,子类的重写方法的指针可以覆盖基类的指针),后一部分是类对象的数据区,<br />      同样前面是基类中定义的数据,后面是子类中定义的数据,当子类指针赋

meiyuli的专栏 999

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C++类对象的内存组织结构:

C++类对象的内存组织结构: 在面向对象语言C++中,每一个对象是内存中的一块内存空间,这块内存空间的的前四个字节是一个指向虚函数列表的指针(每个类中有且只有一个虚函数表,供所有对象共享,前一部分是基类的虚函数指针后面是子类新定义的虚函数指针,子类的重写方法的指针可以覆盖基类的指针),后一部分是类对象的数据区, 同样前面是基类中定义的数据,后面是子类中定义的数据,当子类指针赋值给父类对象时就会使后面的子类数据不可见、子类中新定义的虚函数也不可见,而父类中的虚函数指针的值已经被

meiyuli的专栏 908
上一篇: C++的继承与多态
下一篇: 硬币找零问题(动态规划)
蓬莱道人
博客等级 码龄11年 766粉丝 274原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值