C++类和对象——面向对象的内存模型

目录

一、编译器对属性和方法的处理机制

二、this指针

原理:

this指针代码例程:

三、静态成员

1、静态成员变量:

2、静态成员函数:

静态成员总代码:


一、编译器对属性和方法的处理机制

1、在C语言中“数据”和“处理数据的函数”是分开来声明的,也就是语言本身并没有“数据和函数”之间的关联性、在C++中,通过抽象数据类型(abstract data type ,ADT),在类定义数据和函数,来实现数据的函数直接绑定。

2、在对象的内存模型中,“数据”和“处理数据的函数”是如何存储的。

先来写一个测试代码:

#include <iostream>
 
using namespace std;
 
class C1
{
public:
    int i;  //4
    int j; //4
    int k;  //4
protected:
private:
}; 
 
class C2
{
    public:
        int i; 
        int j; 
        int k; 
    public:
        int getK() { return k; } 
        void setK(int val) { k = val; }  S
}; 

int main()
{
    C1 c1;
    C2 c2;

    cout <<"size c1 ="<< sizeof(c1) << endl;
    cout <<"size c2 ="<< sizeof(c2) << endl;
}

运行结果如下:

一个int类型占四个字节,然后上述代码中一共有三个int类型的成员变量,4*3=12

C2中的成员函数却不占用内存空间,所以我们可以得出:

C++类成员中的成员变量和成员函数是分开存储的

同一类中的存储位置也有差别:

        普通成员变量:

                存储于类的对象当中,与结构体struct变量有相同的内存分布和字节对齐方式

        静态成员变量:

                存储于全局数据区当中

        成员函数:

                存储于代码段当中

内存存储(高位到低位):系统环境固件>>栈>>堆>>数据段>>代码段

二、this指针

原理:

原理性的问题参考这个文章http://t.csdn.cn/BfFJn

本文主要通过Clion的Terminal的调试来体现this指针的

具体步骤:打开Terminal界面:

//在Terminal的命令行中先输入
g++ -g main.cpp -o main //生成了一个main可执行文件
回车
然后 gdb main //运行一下这一个程序用gdb调试

回车.....

出现(gdb)后输入start命令//运行该语句

n//相当于(next)执行下一条语句

print c2.getK  //用print方法打印一下

//打印结果:$1 = {int (C2 * const)} 0x402d10 <C2::getK()>

根据打印结果可知({int (C2 * const)} )编译器自动给形参赋了一个常指针指向c2

(该指针在C++中叫做this指针原型int(C2 * const this)),这是因为C++编译器会将成员函数的第一个形参设计为this指针,this指针指向调用成员函数的首地址,指向成员函数的得对象,在成员函数执行的过程中,正是通过“this指针”才能找到对象所在的地址,在调用c2.getK()的时候相当于getK(&c2);将函数的地址传递了过去。

注意:this的范围使用:非静态的成员函数

this指针代码例程:

#include <iostream>
/*
 * 编译器对属性和方法的处理机制
 * 1、
 * 在C中”数据“和”函数“是分开来声明的也就是说语言本身并没有“数据和函数”之间的关联性。在C++中,
 * 通过抽象数据类型(abstract data type,ADT),在类中定义数据和函数,实现了数据和函数的绑定
 * 2、
 *在对象内存模型中,数据和函数是如何存储的呐
 * */
using namespace std;
class C1
{
public:
    int i; //4
    int j; //4
    int k; //4
protected:
private:
};
class C2
{
public:
    int i;
    int j;
    int k;
public:
    int getK() {
        cout << k << endl;
        return k; }
    void setK(int val) { k = val; }//相当于指向调用函数的对象同时再return k; 也就是 return this->k;
};

void test1(void)//结果显示c1 c2都占12个字节的空间
{
    C1 c1;
    C2 c2;
    cout << sizeof(c1) << endl;
    cout << sizeof(c2) << endl;
}//得出结论C++的函数不占用对象的内存空间,
// 所以可知c++类对象中的成员变量和成员函数是分开存储的
/*
 * 成员变量:
 * 普通成员变量:存储于对象中,与struct变量有相同的内存布局和对齐方式
 * 静态成员变量:存储于全局数据区当中
 * 成员函数:
 * 存储于代码段中
 *
 * 内存:高》底
 * 系统环境固件
 * 栈
 * 堆
 * 数据段
 * 代码段
 * */

int main()
{
//    test1();
    C2 c2,c3;

    c2.k=100;
    c3.k=10;
    c2.getK();
    c3.getK();
    c2.setK(100);
    return 0;
}

//Terminal:调试顺序
/*
 * g++ -g main.cpp -o main //生成了一个main可执行文件
 * 然后运行一下这个程序用gdb调试
 * gdb main
 *  空格、回车
 *  start命令
 *  回车
 *  n(next)//执行下一条语句
 *  用print方法打印一下
 *  print c2.getK
 *  打印结果如下:
 *  $1 = {int (C2 * const)} 0x402d10 <C2::getK()>
 *  编译器自动给形参付了一个常指针指向c2
 *  (该指针再C++中叫做this指针原类型int (C2 * const this))
 *  所以解释:C++编译器会将成员函数的第一个形参设计为this指针,
 *  this指针指向了调用成员函数的首地址,(指向成员函数的对象)
 *  再成员函数执行的过程中,正是通过“this指针”才能找到对象所在的地址
 *  调用c2.getK()时候相当于getK(&c2);将函数的地址传了过去
 *  相当于指向调用函数的对象同时再return k; 也就是 return this->k;
 *  {
 *  打印
 *  print c2.setK
//$1 = {void (C2 * const, int)} 0x402d80 <C2::setK(int)>
 this指针指向调用该成员函数的对象

 * */

三、静态成员

1、静态成员变量:

定义:关键字static可以用于声明一个类的成员,静态成员提供了一个同类的共享机制。

        1.1用法:

#include <iostream>

using namespace std;

class Sheep {
public:
    char name[32];
    int age;

    Sheep()
    {
        cout << "Sheep()" << endl;
        cnt++;
    }

    ~Sheep()
    {
        cnt--;
    }

    static int cnt; //只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域是在类和这类的所有的实例化对象
};

//定义了Sheep这个类中的静态成员变量cnt,并且初始化为0(如果不初始化默认为0)
int Sheep::cnt = 0;

int main() {
    //构造了10个Sheep对象: 购买了10头羊
    Sheep *p = new Sheep[10];
    cout << Sheep::cnt << endl;

    Sheep s1;
    cout << s1.cnt << endl;

    Sheep s2;

    cout << sizeof(s2) << endl;
    cout << Sheep::cnt << endl;
    cout << s1.cnt << endl;
    cout << s2.cnt << endl;

    return 0;
}

1.2静态变量的使用:

1.2.1:类内声明static变量

static int cnt;

1.2.2:类外定义初始化:

int Sheep::cnt = 0;

2、静态成员函数:

1、定义:使用static修饰的成员函数叫做静态成员函数

2、性质:在静态成员函数内不能够访问除静态成员变量以外的其他成员变量。

3、使用:

#include <iostream>

using namespace std;

int cnt = 0;

class Sheep {
public:
    char name[32];
    int age;

    Sheep()
    {
        cout << "Sheep()" << endl;
        cnt++;
    }

    ~Sheep()
    {
        cnt--;
    }

    //静态的成员函数
    static int sheep_num() //没有this指针
    {
       // cout << age << endl; //静态成员函数中不能访问非静态的成员变量!!!
        return cnt; //访问静态成员变量
    }

//public:
private:
    static int cnt; //只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域是在类和这类的所有的实例化对象
};

//定义了Sheep这个类中的静态成员变量cnt,并且初始化为0(如果不初始化默认为0)
int Sheep::cnt = 0;

class Math
{
public:
    static void sin(){}
    static void cos(){}
    static void tan(){}
    static void cotan(){}
};

class searchAlgrithm
{
    //二分查找
};

class sortAlgrithm
{
    //冒泡
    //快排法
    //堆排序
};

int main() {
    //构造了10个Sheep对象: 购买了10头羊
    Sheep *p = new Sheep[10];
 //   cout << Sheep::cnt << endl;

    Sheep s1;
//    cout << s1.cnt << endl;

    Sheep s2;

    cout << sizeof(s2) << endl;
//    cout << Sheep::cnt << endl;
//    cout << s1.cnt << endl;
 //   cout << s2.cnt << endl;

    cout << Sheep::sheep_num() << endl; //建议用类访问静态成员变量和成员函数因为这种访问方式可读性强
    cout << s1.sheep_num() << endl; //不会:sheep_num(&s1);

    Math::sin();

    return 0;
}

注意:静态成员函数不能够访问对象、类中的成员变量。

因为静态成员函数不属于对象。

用处:

静态成员函数的用处:

  • 访问被private/protected修饰静态成员变量

  • 可以实现某些特殊的设计模式:如Singleton(单例模式)

  • 可以封装某些算法

静态成员总代码:

/*
 * ————————————————————————————静态成员变量——————————————————————
 * 定义:关键词static可以用于声明一个类成员,静态变量提供了同类对象的共享机制
 * 把一个类的成员声明为static时,这个类无论由多少个对象被创建这些对象共享这个static成员
 * */
#include <iostream>
using namespace std;

class Sheep
{
public:
    char name[32];
    int age;

    Sheep()//构造函数
    {
        cout << "Sheep()" <<endl;
        cut++;
    }
    ~Sheep()//析构函数
    {
        cut--;
    }
    //静态成员变量
    static int cut;//(之和类有关系)只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域再类和对象中
    //静态成员函数
    static int sheep_num()
    {
//        cout<< age <<endl;//invalid use of member 'Sheep::age' in static member function(非法的访问了非静态成员变量)
        return cut;//访问静态成员变量
    }


};


int Sheep::cut=0;//此处为定义静态变量


/*
 * 静态变量的使用:
 * 现在类外边的C文件中的定义,然后在类中声明
 * */
/*
 * ————————————————————————————静态成员函数——————————————————————
 * 1、把static修饰的成员函数叫做静态成员函数
 * 2、在静态成员函数内不能访问除了静态成员变量之外的其他成员变量
 *
 *
 * */
int main() {

    //构造了10个Sheep对象,场景十只羊
    Sheep * p=new Sheep[10];//构造了10个对象
    cout<<Sheep::cut<<endl;

    Sheep s1;//第十一个对象
    cout<<s1.cut<<endl;

    Sheep s2;//第十二个对象
    cout << sizeof(s2)<<endl;
    cout << Sheep::cut<<endl;
    cout<<s1.cut<<endl;
    cout<<s2.cut<<endl;
    
    Sheep s3;//第十三个对象
    //通过类和对象都能进行静态成员函数的访问
    cout << Sheep::sheep_num() << endl;//建议使用类进行访问静态成员用类进行访问
    cout << s3.sheep_num() << endl;//不会:使用到this指针也就不会sheep_num(&s3)


    return 0;
}
//静态成员的位置在数据段上对象可以共享
/*
 * 作用:
 * 1、用来访问被private:和protected:保护的静态变量
 * 2、实现某些特殊结构的设计模式(单例模式)
 * 3、封装某些算法
 * */

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值