【C++】- 类和对象(!!C++类基本概念!this指针详解)

类和对象

  • 引入类
  • 类的定义
  • 类的访问限定操作符
  • 类的作用域
  • 类的实例化
  • 类对象模型
  • this指针

引入类

在 C++中,引入了一个新的定义----------是一种用户自定义的数据类型,用于封装数据和行为。类可以看作是一个模板或蓝图,描述了一组相关的数据和对这些数据的操作方式。通过类,可以创建具体的对象来使用和操作这些数据。

类是C++面向对象编程的核心,为了便于理解,我们可以将类抽象成一架飞机:
【C++】- 类和对象(!!C++类基本概念!this指针详解)_第1张图片

学习了C语言之后,我们知道了结构体类型,但在C语言结构体内只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。【C++】- 类和对象(!!C++类基本概念!this指针详解)_第2张图片

我们在C++中,用struct实现链表,可以将我们的一系列函数放进去,而这些在C++中更喜欢用class来代替。

在这里插入图片描述

在 C++ 中,structclass 都可以用于定义自定义数据类型,它们的区别主要有以下两点:

  1. 默认访问权限不同:struct 的默认访问权限是公有的,而 class 的默认访问权限是私有的。这意味着在 struct 中定义的成员变量和成员函数是公有的,可以被外部访问;而在 class 中定义的成员变量和成员函数是私有的,只能在类内部访问。

  2. 继承方式不同:在没有显式指定继承方式时,class 的继承方式是私有继承(private),而 struct 的继承方式是公有继承(public)。即如果一个类没有指定继承方式,则其默认继承方式与其类型相同。

类的定义

类的基本定义形式是:

class className
{
    // 类体:由成员函数和成员变量组成
}; 

类体内的内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为成员函数

在这里插入图片描述
【C++】- 类和对象(!!C++类基本概念!this指针详解)_第3张图片这里注意!在类内直接定义的函数 会被默认视为内联函数,但并不意味着所有在类内定义的函数都是内联函数。

内联函数是一种编译器优化的机制,它将函数的定义体直接插入到调用该函数的地方,而不是通过函数调用的方式执行。这样可以减少函数调用的开销,提高程序的执行效率。
就像这样直接插入:
【C++】- 类和对象(!!C++类基本概念!this指针详解)_第4张图片

【C++】- 类和对象(!!C++类基本概念!this指针详解)_第5张图片在类内定义的函数,默认情况下会被视为内联函数。但是,如果函数体过于庞大复杂,编译器可能会忽略内联函数的请求,将其视为普通函数进行处理。因此,并不是所有在类内定义的函数都会被真正地内联。。。

【C++】- 类和对象(!!C++类基本概念!this指针详解)_第6张图片通过使用 inline 关键字,可以告诉编译器将该函数作为内联函数处理。

☃ 需要注意的是,内联函数适用于简单短小的函数,且在多处调用的情况下才能发挥优势。对于复杂的函数或只在少数地方调用的函数,使用内联可能导致代码膨胀,反而降低性能。因此,在确定是否使用内联函数时,需要综合考虑函数的规模、调用频率以及性能需求等因素。

?当我们单纯的定义一个类,定义任何成员变量时,系统会为这个类开空间吗

在 C++ 中,一个类的对象大小至少为 1 字节,即使这个类没有任何成员变量。这是因为每个对象都必须在内存中占据至少一个字节的空间。
这个字节通常用于对象的地址,也就是对象所在内存地址的第一个字节。即使这个字节不存储有效数据,但是它也是必需的,因为它用于确定对象在内存中的位置和边界。

类的访问限定操作符

在C++中,类的访问限定符用于控制类的成员变量和成员函数的访问权限。C++中为我们提供了三种访问限定符:public、private和protected。

1. public:

  • 成员变量和成员函数声明为public的可以在类的外部和内部被访问。
  • public成员可以通过对象直接访问或通过类的对象调用。
  • public成员在类的继承层次中也可以被派生类访问。

2. private:

  • 成员变量和成员函数声明为private的只能在类的内部被访问。
  • private成员不能通过对象直接访问,只能通过类的成员函数来访问。
  • private成员对于类的外部是不可见的。

3. protected:

  • 成员变量和成员函数声明为protected的可以在类的内部被访问。
  • protected成员在类的继承层次中可以被派生类访问,但对于类的外部是不可见的。
  • protected成员不能通过对象直接访问,只能通过类的成员函数来访问。

默认情况下,C++中的类成员的访问限定符是private。这意味着如果没有显式地指定访问限定符,那么成员变量和成员函数都将被视为private成员。

代码演示:

#include 
using namespace std;

class MyClass {
public:
    int publicVar;
    void publicFunc() {
        cout << "publicFunc is called" << endl;
    }

protected:
    int protectedVar;
    void protectedFunc() {
        cout << "protectedFunc is called" << endl;
    }

private:
    int privateVar;
    void privateFunc() {
        cout << "privateFunc is called" << endl;
    }
};

int main() {
    MyClass obj;
    obj.publicVar = 1;
    obj.publicFunc();
    return 0;
}

在上面的代码中,我们定义了一个名为MyClass的类,并且使用了三种不同的访问限定符来限制成员的访问权限。在main函数中,我们创建了一个MyClass类的对象obj,并且访问了publicVar和publicFunc方法,因为它们都是公共成员。但是我们不能访问protectedVar、protectedFunc、privateVar和privateFunc方法,因为它们只能在类内部访问。如果尝试访问它们,编译器会报错。

通过使用不同的访问限定符,我们可以控制类的成员在何处可见和可访问。这有助于实现信息隐藏和封装的概念,使得类的实现细节对于外部用户来说是不可见的,从而提高代码的安全性和可维护性。

类的作用域

在C++中,类的作用域是指类中成员的可见范围。类的作用域可以分为两个部分:类的内部作用域和类的外部作用域。

  • 类的内部作用域:在类的内部,成员函数和成员变量可以直接访问类中的其他成员,无需使用作用域解析运算符::来限定。在成员函数中,可以直接访问该类的所有成员,包括私有、保护和公共成员。
  • 类的外部作用域:在类的外部,需要使用作用域解析运算符::来限定访问类中的成员。通过类名加上作用域解析运算符,可以访问该类的公共成员和静态成员。私有和保护成员无法在类外部直接访问。

在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。作用域操作符在博主【C++】- 类和对象(!!C++类基本概念!this指针详解)_第7张图片C++入门篇 有讲解

类的实例化

类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图。
【C++】- 类和对象(!!C++类基本概念!this指针详解)_第8张图片

类对象模型

类在内存中的存储模式如下:
【C++】- 类和对象(!!C++类基本概念!this指针详解)_第9张图片

在计算类对象的大小时,一般只需要考虑成员变量的大小,而不需要计算成员函数的大小。成员函数在对象中并不占据实际的内存空间,它们只是一组指向类的成员函数代码的指针。这些指针共享存储在类的静态区域中,并且对于每个类的所有对象来说是相同的。因此,成员函数不会影响类对象的大小。

总结起来,计算类对象的大小只需要考虑成员变量的大小,而成员函数和虚函数表对于类对象的大小没有直接影响。

this指针

在C++中,每个对象都有一个指向自己的指针,这个指针就是this指针。this指针是一个隐含于每个非静态成员函数中的特殊指针,它指向调用该函数的对象。在C++中,成员函数可以直接访问对象的数据成员,因为在成员函数内部,this指针指向当前对象的地址,通过this指针可以访问对象的所有成员变量和成员函数。

先来看一段简单的代码:

class Date
{ 
public:
 void Init(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 void Print()
 {
 cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }
private:
 int _year;     // 年
 int _month;    // 月
 int _day;      // 日
};
int main()
{
 Date d1, d2;
 d1.Init(2022,1,11);
 d2.Init(2022, 1, 12);
 d1.Print();
 d2.Print();
 return 0;
}

???Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

【C++】- 类和对象(!!C++类基本概念!this指针详解)_第10张图片在C++中,对象在调用成员函数时,编译器会自动将该对象的地址作为this指针传递给成员函数。在Init函数中,通过this指针访问对象的成员变量,确保将值设置到正确的对象中。

因此,当d1调用Init函数时,Init函数内部的操作会通过this指针访问d1对象的成员变量,即将值设置到d1对象的_year、_month和_day成员变量中;同样,当d2调用Init函数时,Init函数内部的操作会通过this指针访问d2对象的成员变量,将值设置到d2对象的成员变量中。这样就实现了不同对象之间的区分。当然最后,当d1和d2调用Print函数时,会打印出各自的年月日信息。

只不过这些所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。【C++】- 类和对象(!!C++类基本概念!this指针详解)_第11张图片

在这里插入图片描述

this指针在C++中具有以下特性:

  1. this指针的类型是类类型的指针,即类类型* const。这意味着this指针是一个常量指针,指向当前对象的地址,不可以被修改。

  2. this指针只能在成员函数内部使用。它代表当前对象的地址,并且只有在成员函数内部才能访问到该指针。

  3. this指针本质上是成员函数的一个隐式形参。当对象调用成员函数时,编译器会将对象的地址作为实参传递给this指针,使得成员函数可以通过this指针来访问对象的成员变量和成员函数。

  4. this指针是成员函数的第一个隐含参数,一般情况下由编译器自动传递,不需要用户显式传递。

  5. 对象本身并不存储this指针,它只是在成员函数调用时被传递给this指针。

通过使用this指针,我们可以在成员函数内部访问对象的成员变量和函数,确保每个对象在调用成员函数时可以正确地操作自己的数据。this指针的存在使得对象的成员函数可以区分不同的对象,并在函数内部对各个对象进行操作。

【C++】- 类和对象(!!C++类基本概念!this指针详解)_第12张图片this指针是C++中一个非常重要的概念,也是面向对象编程中不可或缺的一部分。它可以让成员函数访问对象的成员变量和成员函数,避免命名冲突,返回对象本身的引用等。在使用this指针时,需要注意当前对象是否存在,以及函数内部是否正确处理对象的生命周期和有效性。

你可能感兴趣的:(c++,java,jvm)