【C++】面向对象/this指针的使用


面向对象:行为和属性
人的属性:性别,爱好,家庭住址等
人的行为:打羽毛球,上班,吃饭,睡觉等
行为需要用方法来实现,属性需要变量来定义
实例化:需要去创建对象。通过对象访问成员方法和成员变量。

面向对象


有对象一定有空间
有空间不一定有对象
为什么创建一个空对象 ,其所占字节数为1?
原因:C++ 编译器会给每个空对象也分配一个字节空间,是为区分空对象占内存位置。


  • 类在设计的时候,可以对属性和行为放在不同的权限下,加以控制
    访问权限有三种:(访问限定符)
  1. public 公有权限 类内 可以访问 类外可以访问
  2. protected 保护权限 类外不可以 儿子可以访问父亲中的保护内容
  3. private 私有权限 除了类内 均不可访问
    (三种权限体现了封装性
    如下:
class   Goods
{
    public:
            int size;
    private:
           int  num;
    protect:
            int age; 
  
}//分号不能少,这是一条说明语句
int main()
{
    Goods good;
    good.size =10; //可以访问
    good.num =100; //不可以
    good.age  =10;   //不可以
}

如下:成员属性和和成员方法被封装成为一个整体。

class   Goods
{
    private:
           int  Amout;
           char Name[LEN];
           float Price;
  public:
//内联       inline void RegisterGoods(char[],int ,float);  //输入数据
          char GetName(char[]);   //读取商品名
          float GetPrice(void);    //读取商品单价
}inline void Goods::RegisterGoods(const char *name,int amout ,float price)  
 {
     strcpy_(Name,LEN,name);//字符串拷贝函数,拷贝的长度
     Amout = amout;
     Price = price; //实现了类中的私有属性的访问。
 }
 char Goods::GetName(char name[])   //读取商品名
 {
   strcpy(Name,name);
 }
  1. 3个数据成员被说明为私有,而3个函数成员被说明为公有;这就是说,如果从外部对3个数据成员来操作的话,只能通过3个公有函数来完成,数据受到了良好的保护,不易受到外部环境的影响。共有函数集定义了类的接口。
  2. 类是一种数据类型,定义时,系统不为类分配空间,所以不能对类的数据成员进行初始化,类中的任何数据成员也不能使用关键字extern,auto或register限定其存储类型。
    如果要访问类中的成员,必须实例化对象。
  3. 成员函数的定义在类的说明之后:
    返回类型 类名::函数名(参数列表)
    如:(同返回类型,同参数列表 )
};
void Goods::GetName(char[]){ 函数体}

【使用对象,可以调用成员方法访问私有属性。】


类中的成员属性存在数据区,成员方法存在代码区

  • 那么内存是如何给每一个对象分配空间呢?
    如下图:
    请添加图片描述
    请添加图片描述
    每一个对象共享同一个方法,每个对象调用方法的,会去给各自访问的成员属性开辟空间。
    也就是:【内存为每个对象开辟一个数据区,共享一个代码区。
  • 那每个对象如何知道自己通过成员方法访问的成员属性是自己的呢?
    那就要说this指针的使用:
  1. 第一步,识别和记录 类体中【属性名称,类型,访问限定符】,不管属性定义在类中的哪个位置,都会先识别属性。对私有化的【数据区】数据进行处理。
  2. 第二步,识别和记录 类体中函数原型(返回类型,函数名,形参列表), 形参的默认值,访问限定符,不识别函数体。对代码区的函数声明进行处理
    只识别声明,不识别函数体,那函数定义的时候,调用函数,就不需要考虑位置。
    如下:
class stu
{
   private:
        char Name[10];
        char Sex[10];
       publicchar GetName(char[]);
            char GetSex(char[]);    
}
char stu::GetName(char *name)
{
    this->GetSex();//因为已经在第二部识别记录过类中函数的声明,所以加上this指针,即便GetSex在GetName后定义,也能调用。
}
char stu::GetSex(char *sex)
{
    this->Sex = sex;

}

  1. 第三步,改写类中定义的函数的形参列表和函数体,改写对象调用成员函数的形式。就是加上this指针 其实就相当于把对象的地址传给this指针,这样就相当于每个对象去控制各自私有成员属性。 对成员函数进行改写
    如下:
class Goods
{
public:
void RegisterGoods(const char *name,int amout ,float price);  
void RegisterGoods(Goods *this,const char *name,int amout ,float price) ; 
void CountTotal(void);
void CountTotal(Goods *this);
};

改写函数体

void Goods::RegisterGoods(const char *name,int amout ,float price)  
 {
     strcpy_(Name,LEN,name);//字符串拷贝函数,拷贝的长度
     Amout = amout;
     Price = price; //实现了类中的私有属性的访问。
 }
 void Goods::RegisterGoods(Goods *this,const char *name,int amout ,float price)  
 {
     strcpy_(this->Name,LEN,name);//字符串拷贝函数,拷贝的长度
     this->Amout = amout;
     this->Price = price; //实现了类中的私有属性的访问。
     }
     int main()
     {
       Goods book,tea; //对象没有this指针,是在调用的时候将对象传进去
       book.RegisterGoods("muzhaoy",20,19.9);
       //  RegisterGoods(&Book,"muzhaoy",20,19.9);
        tea.RegisterGoods("shiqiany",30,18.9);
        //  RegisterGoods(&tea,"shiqiany",30,18.9);
        book.countTotal();
       // countTotal(&book);
        tea.countTotal();
        //countTotal(&tea);
        

所以,从逻辑上讲,是对象调用方法,从底层讲,其实将当前对象作为地址传递给成员方法。
如果给每一个对象分配成员方法,所占内存太大,所以采取上述方法。只耗损了一个this指针。四字节。

  • 为了防止人为修改this,导致无法识别成员因此系统给this指针加了const
    如下:
void RegisterGoods(Goods *const this,const char *name,int amout ,float price) ; 
  • 当对象调用成员函数的时候才有this指针,不调用时,this指针不存在,this指针存在于成员函数内部,且每次对对象操作完,this指针就会消失。
    当函数调用结束,this指针就不存在了
  • 不是类的成员方法,全局函数按照普通函数编译,不会按照类的方法编译,给予this指针。外部函数一定没有this指针。

问题一:是不是类的成员函数一定要加this指针?
答:不是,
类中的静态成员函数,友元函数,内联函数没有this指针。

  1. 静态成员函数只能使用静态成员变量。静态成员变量不依赖类和this指针。
  2. 友元函数的定义在类外,不需要通过对象来访问。
  3. 如果是内联函数就不需要,传入this,因为会在调用点代码直接展开,根本不需要开辟栈帧,也就不需要this指针去指向开辟各自的私有成员属性的空间。
    问题二:对象中有没有this指针?
    答,没有,对象调用成员方法,是将对象的地址传给成员方法,从而达到每个对象独立的访问私有成员属性。

进一步了解是this指针:

  • 在成员函数后面加const
    float GetTotal_value()const //后面加const,等价于下面。
    float GetTotal_value(const Goods *const this)
    {
    int x= this -> Amout;
    this -> Amout =1000; //是错的,因为this指针的指向作用被const限定了。
    //*this 不能变

}
Goods c1,c2
//c1.GetTotal_value(); == GetTotal_value(&c1)
const Goods *const this,可以指向对象c1,但无法指向对象二。并且指向的值也不能改变。
同样的c2.GetTotal_value(); 也是如此。

  • 常对象,常方法,和 普通对象,普通方法的关系
    常对象只能调用常方法
    如下:
class Coods
{
    privatechar Name[21];
    int Amout ;
    float Price;

普通方法:

pubilc:
   float Getprice()    //   float Getprice(Coods *const price){......} 
   {
     return this->Price;
   }
  

float Getprice(Coods *const price){......}


常方法:
float GetTotal_value(const Coods *const price)

     float GetTotal_value()const  //float GetTotal_value(const Coods *const price)
     {  
           return Total_value;
       }
};
Coods c1 = {"c++",2,12.3};
const Coods c2 = {"java",3,13.4};

c1. Getprice() //普通函数可以调用普通方法
c1.GetTotal_value()//普通函数可以调用常方法,能力被缩小。
c2. Getprice() //常对象调用普通方法,不可以能力被扩大。
可以理解为 :

int a = 10
const int *p = &a;
int *const s = p;//错误的!!!

c2. GetTotal_value()//常对象调用常方法。
结论:常对象可以调用常方法,不可以调用普通方法
普通对象都能调。

静态成员变量:

  1. 无论构造多少个对象,一个类只有一份,
  2. 存储在数据区。
  3. 必须在类外的【.cpp文件中】进行初始化,切只能初始化一次。
  4. 静态成员变量可以不依赖对象,不依赖this指针。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值