> 文档中心 > 13天带你了解C++ ---DAY4 类的相关定义及操作,this指针

13天带你了解C++ ---DAY4 类的相关定义及操作,this指针

目录

1.类的引入

2.类成员的访问

3.访问限定符

4.类和对象的区别

5.类对象模型

  5.1 类的大小

 5.2结构体内存对齐原则

6.this指针

6.1this引入

6.2验证*this


1.类的引入

        在C语言中,描述一个事物的属性时通常使用结构体,结构体方便我们统一调度这些变量属性.但是C语言结构体中是不能放函数的。我们只好将功能函数定义在结构体外,在遇见大项目的时候,各种函数名非常容易记混,会增加出错的风险。所以在C++中,引入类概念,就很好的解决了问题。它规定结构体中是可以使用定义变量和函数的,这极大的提升了我们的代码幸福感。

那么,类应该如何定义呢?

         c++在定义时有两种方式,第一种是函数声明放在类外,另一种是函数声明和定义都放在类体中,这里推荐第一种,声明定义分离能增加代码规范性和可读性。

C语言中仿类定义struct student{    char name[20];    int age;    char sex;    char num[20];};  void exam(){     printf("%s",name); }  void homework(){     printf("%d",name); }c++类的定义class student{      //此处为了方便演示,将声明和定义放在类中    private: char name[20]; int age; char sex; char num[20];    public:  void exam(){     cout<<name<<endl; }  void homework(){     cout<<sex; }};    //这个封号不能省略哦

c++将数据与方法封装在一起,逻辑明显比C语言清晰,内聚性更高。在大型工程中,这个优势会更加明显。

此处体现了面向对象三大特性(继承、封装、多态)的封装特性,将数据与与操作数据的方法有机结合,对外暴露出公开接口以供使用。

2.类成员的访问

        因为函数内聚性,大多数情况我使用的是类内直接操作变量,我们可以直接像访问普通变量一样访问,在类外进行访问时有以下方法。

1.在创建对象以后可以使用点号来访问成员变量和成员函数,和结构体访问他的成员类似

class student{      char name[20]; int age; char sex; char num[20];    public:  void exam(){     cout<<name<<endl; }  void homework(){     cout<<sex; }};    int main(){    student stu;    stu.name="小米";    stu.age=12;    stu.num="128";    return 0;}

2.使用new关键字在堆上创建对象

int main(){//new操作符创建是匿名对象,需要一个对象指针来访问它    student *stu=new student;    *name="小米";    *age=12;    *num="128";    return 0;}

3.访问限定符

        在上边代码中,提到了public和private关键字,它们都是访问限定符。访问限定符可以对数据访问设置权限。比如在类中的sex变量,你不想让类外的方法访问到,就可以使用private关键字,增加了数据安全性。

常见访问限定符分为四种,default,public,private,protect。

使用方法:在变量之前加上访问限定符,访问作用范围是到下一个访问限定符之前

        default:类定义中若未设置访问限定符,默认是default。

        public:既可以在类中引用和修改数据,也可以在类外引用和修改

        private:类中的private成员只能被该类的成员访问。

        protected:类的protected数据成员只能被类成员函数、子类函数访问,不能被其他任何访问。

        private和protected区别:它们都能被类成员访问,但是前者只能不能被任何除类成员外的函数访问,后者可以在继承时被子类访问。

举个栗子:private

 #include      using namespace std;     class student{   private:string name;int age;char sex;string num; void exam(){    cout<<name<<endl;}      };     int main(){   student stu; stu.name="小米";  stu.age=12; stu.num="41909310221";  return 0;      }    

   错误:name是私有成员,不能访问

4.类和对象的区别

        类是一套模具,里边定义了各种标准和参数,用这个模具可以实例化出许多对象。对象是实实在在存在的,在对象身上可以附加各种数值属性,然后操作对象完成动作。类里边不附加数值,而对象实例化之后添加属性。

5.类对象模型

        5.1 类的大小

#include    using namespace std; class student{ public:     int age;     char sex;      };    class student1{int age;     char sex; void exam(){ int a=0; }     };    int main(){ student stu;     student1 stu1;   stu.age=12; stu1.age=12;cout<<sizeof(stu)<<endl; cout<<sizeof(stu1)<<endl;return 0;    }    

结论:1.类的对象大小遵循内存对齐原则

           2.与类中是否存在函数以及静态成员变量无关

           3.空类实例化大小为1

 解释:

             内存对齐原则方便操作系统读取

            静态成员变量和成员函数并不是每个对象都复制一份,而是内存中只有一份,所有对象共享使用,这样就能避免每个对象复制一份,节省空间。静态成员变量放在栈上,函数放在代码段。

             对象在调用时会进行函数压栈,假如类的大小为0,那么下一个函数就会占用这个位置,系统调用时在这个地址找到的就是第二个函数。

 5.2结构体内存对齐原则

        在结构体中内存分布并不是像顺序表那样连续排列,而是遵守内存对齐规则进行排列,这样能提高读取效率。

对齐规则:

                1.第一个成员在结构体变量偏移量为0 的地址处。(设置第一个变量时用的)

                2.结构体总大小为最大对齐数的整数倍。(设置最后一个变量时用的)

                3.其他成员变量要对齐到对齐数的整数倍的地址处。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux默认值为4.(设置中间变量时用的)

                4. 如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。(设置成员有结构体时用的)

举个栗子....

#include    int main(){   typedef struct A{ int a; double b; short c;      }size;     printf("%ld\n",sizeof(size));      return 0;    }    

解释:a为int型,占4个字节,根据规则1,占用0~3地址

           b为double型,占8个字节,根据规则3,占用8~15地址

           c为short型,占2个字节,根据规则1,占用16~18地址

           根据 规则2,结构体总大小为最大对齐数的整数倍,最大对齐数位为8,目前排到18,下一个整数倍是24,所以结构体大小为24

6.this指针

6.1this引入

        当我们实例化一个对象之后,我们势必会通过对象调用类中的方法。比如以下代码

#include      using namespace std;     class This{ public:   void a(){     cout<<"调用我!"<<endl;   }      };     int main(){ This d1; d1.a();return 0;   }  

 问题:前边我们讲到对象里边只有变量,函数是放在代码段的,那么为什么d1未给参数就可以调用不属于自己的成员函数a呢?

        这是因为在调用成员函数时,编译器会偷偷在函数参数列表增加一个this指针,哪个对象调用成员函数,这个this指针就指向谁。实际编译执行的代码应该是下边代码,这个this指针就指向d1对象。

void a(*this){     cout<<"调用我!"<<endl;   }    

6.2验证*this

        验证this存在性 

       既然编译器后台调用的是this指针,那就意味着我们也可以显式调用,this指针类型为

 类类型* const

#include      using namespace std;     class This{ public:      int _a=10;    void A(/*This* this */){ cout<<(*this)._a<<endl;      }  };    int main(){    This d1;    d1.A();    return 0;  } 

结论:我们参数列表中没有this,但是我们显式调用,this指针确实存在。

        验证this指向d1对象

#include      using namespace std;     class This{ public:   int _a=10;   void A(/*This* this */){cout<<"this存的地址:"<<this<<endl;     //打印this存的地址   This* const & _this=this;   cout<<"存this的地址:"<<&_this<<endl;   //this地址不允许直接打印,这里给this取别名打印 }    }; int main(){      This d1;      d1.A();      cout<<"d1的地址"<<&d1<<endl; //打印d1地址 return 0;  }    

结论:this存的地址就是d1对象地址,题目可证

总结:今天我们认识了类的定义,类成员访问,访问限定符,类对象模型,以及this指针。

所以,接下来的知识,明天再来探索吧。

艺术字体转换器