C++——类和对象(一)

面向对象

概念:面向对象是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例,将对象作为程序的基本单元。将程序和数据封装其中,以提高软件的重用性,灵活性和扩展性。

三大特性: 封装,继承,多态

类(class/struct):数据(成员变量)、程序(成员函数)

三种访问限定符:public(共有)、protected(保护)、private(私有)。
1、public成员可从类外部直接访问,private/protected成员不能从类外部直接访问。
2、每个限定符在类体中可使用多次,它的作用域是从该限定符出现开始到下一个限定符之前或类体结束前。
3、类体中如果没有定义限定符,则默认为私有的。
4、类的访问限定符体现了面对对象的封装性。

作用域:局部域,全局域,类域,名字空间域

类的作用域:
1、每个类都定义了自己的作用域,类的成员(成员函数/成员变量)都是类的这个作用域内,成员函数可任意访问成员变量和其它成员函数。
2、对象可以通过,直接访问公有成员,指向对象的指针通过->也可以直接访问对象的公有成员。
3、在类体外定义成员,需要使用::作用域解析符指明成员属于哪个类域。

例:定义一个简单的类

class Person        //类名
{
public:         // 访问限定符
    void Dispaly()      // 成员函数
    {}
public:
    char*    _name;         //  名字   成员变量
    char*    _sex;          //  性别
    int      _age;          //  年龄
}; 


成员函数的声明和定义
1、类内定义成员函数

class Person
{
public:
    void Dispaly()
    {
        cout<<_name<<"_"<<_sex<<"-"<<_age<<end1;
    }
public:
    char*    _name;
    char*    _sex;
    int      _age;
};

2、类外定义成员函数

class Person
{
public:
    void Dispaly();
public:
    char*    _name;
    char*    _sex;
    int        _age;
}

void Person::Display()
{
    cout<<_name<<"-"<<_sex<<"-"<<_age<<end1;
}


类实例化对象
1、类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。
2、一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间存储类成员变量。
3、做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样的类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。

class Person
{
public:
    void Display()
    {}
public:
    char*    _name;
    char*    _sex;
    int      _age;
};

void Test()
{
    Person p;    //这就是类实例化出的对象
    p._name = "jack";
    p._age = 10;
    p._sex = "男";
    p.Display();
}


类对象存储模型
每个对象的大小为类中所有成员变量的大小之和,当然这个遵循内存对其原则。
这里写图片描述

那么为什么要内存对齐呢?

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。一般我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。

内存对齐规则:

1、第一个成员在与结构体变量偏移量为0的地址处。
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地质处。
对齐数 =编译器默认的一个对齐数与该成员大小的较小值。
VS中默认的值为8
gcc中默认值为4
3、结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
4、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

内存对齐的计算:

1.结构体中的每个元素按照定义顺序一个个放入内存中,但并不是紧密排列的,从结构体存储的首地址开始,元素都按照自己的大小来划分内存,所以元素放置的位置一定在自己宽度的整数倍上开始。
2.根据第一个原则计算后,检查计算出的结果是不是存储单元中最宽元素长度的整数倍,如果不是,则要补齐为它的整数倍。

class A
{
    char a;
    double b;
    int c;
};

此例中,a占了内存中第0个字节,b进入存储单元的时候,以自己的8个字节进行划分,认为第一个 8字节已经被占用,所以b占了第8到第15个字节,当c进入存储单元的时候,以自己的4个字节进行划分,认为前三个 四字节的空间已经被占用,所以c占用第16到第19个字节。即计算出的结果为20,但20不为8的整数倍,所以补齐应为24。

空类的计算:

空类是指类中没有任何成员。

在C++下,空类和空结构体的大小是1(编译器相关),这是为什么呢?为什么不是0?
这是因为,C++标准中规定,“no object shall have the same address in memory as any other variable” ,就是任何不同的对象不能拥有相同的内存地址。 如果空类大小为0,若我们声明一个这个类的对象数组,那么数组中的每个对象都拥有了相同的地址,这显然是违背标准的
所以C++标准规定不同的对象不能拥有相同的地址。那么怎样才能保证这个条件被满足呢?最简单的方法莫过于不允许任何类型的大小为0。所以编译器为每个空类或者空结构体都增加了一个虚设的字节(有的编译器可能加的更多),这样这些空类和空结构的大小就不会是0,就可以保证他们的对象拥有彼此独立的地址。

猜你喜欢

转载自blog.csdn.net/yummy_alice/article/details/81097366
今日推荐