江苏省建设招标网站,怎么做公司logo,策划推广活动方案,正规网站建设商家思考#xff1a;对于实现平面一个点的参数化。C的class封装看起来比C的struct更加的复杂#xff0c;是否意味着产生更多的开销呢#xff1f;
实际上并没有#xff0c;类的封装不会产生额外的开销#xff0c;其实#xff0c;C中在布局以及存取上的额外开销是virtual引起的…思考对于实现平面一个点的参数化。C的class封装看起来比C的struct更加的复杂是否意味着产生更多的开销呢
实际上并没有类的封装不会产生额外的开销其实C中在布局以及存取上的额外开销是virtual引起的。
C对象模式
在C中有两种class data members静态成员和非静态成员。有三种class member functions:静态的非静态的以及虚函数
C对象模型
Nonstatic datamembers 被配置于每一个class object之内。static data members则被存放在个别的class object之外。
static 和nonstatic function members也被存放在class object之外仅一份
virtual fuction每一个class产生一堆指向virtual tablevtbl中每一个class object被安插一个指针vptr指向相关的virtual table
(图示)
关于继承
继承关系也可指定为虚拟也就是共享
图示
在虚拟继承的情况下base class不管在继承串链中被派生多少回永远只存在一个实例subobject
图示
对象模型如何影响程序 (图示
对象的差异
程序模型类C
char boy[] Danny;
char *p_son;
...
p_son new char [strlen(boy) 1];
strcpy(p_son,boy);
...
if(!strcmp(p_son,boy))take_to_disneyland(boy)
抽象数据类型ADT
string girl Anna;
string daughter;
...
//string :: operator ()
daughter girl;
//string::operator()
if(girl daughter)take_to_disneyland(girl);
面对对象编程
void
check_in(Library_materials *pmat)
{
if(pmat-late() )pmat-fine();
pmat-check_in();
if(Lender *plend pmat-reserved())pmat-notify(plend);
}
多态实现
在C中多态只存在于一个个的public class体系中
有这样三种多态支持:
经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向public base type的指针
shape *ps new circle();
经由virtual fuction机制
ps-rotate();
经由dynamic_cast和typeid运算符;
if(circle pc dynamic_castcircle(ps))..
思考:需要多大内存才能够表现一个class object 非静态数据成员(non-static data members):非静态数据成员是每个类对象都需要独立分配的,所以其大小需计算在内。
虚函数表指针(vptr):如果类含有虚函数,则需要一个指针指向虚函数表,用于动态绑定。这个指针的大小通常是机器字长,比如64位系统为8字节。
内存对齐填充(padding):为了优化内存访问效率,编译器会在类成员之间插入内存对齐填充。
其他系统占用空间:除了类自身需要的空间外,一些编译器和系统会在类对象中预留一些额外空间,例如运行时类型信息(RTTI)。
所以一个类对象所需内存的计算公式概略为:对象内存 非静态数据成员大小总和 (含虚函数则加上vptr指针大小) 填充大小 其他系统占用大小
其中除了非静态数据成员外,其他部分大小在不同系统和编译器下可能有所不同。
一个更准确的计算对象大小的方法是:在程序中使用sizeof运算符,它会返回这个平台下该类对象的确切字节大小。
注意:
类中静态数据成员(static data member)与对象的内存大小无关。
静态数据成员不属于类的任何一个对象,只会在程序的整个生命周期内有一份内存拷贝存在。
所以静态数据成员不会影响每个类对象实例的内存需求。 指针的类型
例子:
ZooAnimal *px;
int *pi;
Arraystring*pta;
从内存上面看这几个指针没有什么区别大小是一个机器地址。word
但是其实“指针类型”会教导编译器如何解释某个特定地址中的内存内容以及大小。
图示 进一步探讨:
Bear b; ZooAnimal zab; //译注:这会引起切割(sliced) //调用 ZOOAnimal::rotate() za.rotate();
为什么rotate所调用的是ZooAnimal实例而不是Bear实例?此外如果初始化函数(译注:应用于上述assignment操作发生时)将一个object内容完整拷贝到另个object去为什么za的vptr 不指向Bear的virtual table?
在ZooAnimal za b;这行代码中,使用基类ZooAnimal的引用或指针初始化时,编译器会:
为za分配一个ZooAnimal类型的空间把b对象中的ZooAnimal部分的数据拷贝过来
也就是说,这个赋值操作生成了一个新的ZooAnimal对象,它只包含了原b对象中的ZooAnimal部分的数据和函数,丢失了b作为Bear的额外信息。
然后za调用rotate()时,编译器根据静态类型(ZooAnimal)调用ZooAnimal::rotate(),而不是动态类型Bear::rotate()。
如果想保留全部信息,可以使用指针或引用:cpp Bear b; ZooAnimal* za b; za-rotate(); // 调用Bear::rotate()
或者使用动态绑定:cpp Bear b; ZooAnimal za b; za.rotate(); // 调用Bear::rotate()
编译器在将一个class object指定给另一个class object之间做出仲裁编译器必须保证如果某个object含义一个或者以上的vptrs那些vptrs不会被base class 改变。
补充:
当一个base class object 被直接初始化为(或是被指定为)一个 derived classobject 时derivedobject 就会被切(sliced)以塞入较小的 base type 内存中derivedtype将没有留下任何蛛丝马迹。多态于是不再呈现而一个严格的编译器可以在编译时期解析一个“通过此object而触发的virtualfunction调用操作”因而回避virtual机制。如果virtualfunction 被定义为inline则更有效率上的大收获。 本文由博客一文多发平台 OpenWrite 发布