【三、类中的静态成员】静态成员变量与静态成员函数(static关键字、this指针)

简介: 【三、类中的静态成员】静态成员变量与静态成员函数(static关键字、this指针)

基本语法

  • 静态成员提供了一个同类对象的共享机制,静态成员变量属于整个类,该类所定义的对象共享同一个静态成员变量(无论定义多少个对象,他们的static成员变量都是同一个)。
  • 静态成员变量必须在外部声明并初始化。
  • 静态成员函数中不能使用非静态成员变量,因为静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针。静态成员是属于整个类的,他不依赖于某个对象,而普通成员函数专属于类定义的个某个对象,这时候如果调用该静态成员函数,编译器不知道该函数中被引用的普通成员变量属于哪个具体对象,故报错(具体将在下面代码中详细分析)。

代码分析

代码如下:

#include <iostream>
using namespace std;
class MyClassA
{
public:
  MyClassA()
  {
    a = 10;
    cout << "无参构造函数调用" << endl;
  }
  void PrintA()
  {
    cout << "静态成员 a = " << a << endl;
  }
public:
  static int a;
};
int MyClassA::a = 0; //必须在外部定义!!!否则报错
           //错误 LNK2001 无法解析的外部符号 "public: static int MyClassA::a" 
//静态成员变量测试
void FuncTest1()
{
  MyClassA A1, A2;
  A1.PrintA();
  //静态成员变量的第一种访问方式
  A2.a++;
  A1.PrintA();
  //静态成员变量的第二种访问方式
  MyClassA::a++;
  A1.PrintA();
  A2.PrintA();
}
class MyClassB
{
public:
  static void PrintStaticValue()
  {
    cout << "静态成员函数中的静态变量   " << "b2 = " << b2 << endl;
  }
  static void PrintValue()
  {
    //cout << "静态成员函数中的非静态变量   " << "b1 = " << b1 << endl;
    //错误(活动)  E0245 非静态成员引用必须与特定对象相对
    //错误  C2597 对非静态成员“MyClassB::b1”的非法引用 
  }
  /*
  静态成员函数中只能使用静态变量,不能使用非静态成员变量,因为非静态成员变量是属于某个对象的,
  当我们  MyClassB::PrintValue() 的时候,编译器不知道该使用哪个对象(B1还是B2还是B3...)的非
  成员变量b1
  */
private:
  int b1;
  static int b2;
};
int MyClassB::b2 = 0;
//静态成员函数测试
void FuncTest2()
{
  MyClassB B;
  //静态成员函数的第一种调用方式
  B.PrintStaticValue();
  //静态成员函数的第二种调用方式
  MyClassB::PrintStaticValue();
  MyClassB B1, B2, B3;
  //MyClassB::PrintValue();
  //我应该使用哪个b1???是打印B1的b1,还是打印B2的b1,又或者是B3的b1?
  //故报错
}
int main()
{
  FuncTest1();
  FuncTest2();
  system("pause");
  return 0;
}

成员变量与成员函数的存储与this指针

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

  • 成员变量:
    ①普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节 对齐方式。
    ②静态成员变量:存储于全局数据区中。
  • 成员函数:存储于代码段中。

既然类的成员函数存储在代码区,也就是说所有的对象共用一块代码,那么当具体对象调用成员函数的时候,怎么区分成员函数中使用的变量是哪个对象的呢?比如:

class MyClass
{
public:
    void PrintValue()
    {
        a = 10;
        cout << a << endl;
    }
public:
    int a;
};
int main()
{
    MyClass A1, A2, A3;
    A1.PrintValue();
    system("pause");
    return 0;
}

在上段代码中,PrintValue函数中用的变量a是A1的还是A2的还是A3的呢?

C++编译器会对成员函数进行内部处理,加一个this指针,this指针指向调用该成员函数的对象,这样就知道是哪个对象调用了该成员函数,并使用该对象的成员变量值。代码如下:

void PrintValue(MyClass* this)
{
  this->a = 10;
    cout << this->a << endl;
}

在调用的时候

A1.PrintValue();

会被转化为

PrintValue(&A1);

由此可见,这也是使用了C语言的指针实现的。实际上,面向对象也是在面向过程的基础上实现的,只不过是在此基础上加了一层封装,对用户进行了隐藏而已。

对于静态成员函数,不会做这种转化,因为静态成员函数是属于整个类的,这也正是为什么静态成员函数中不能使用非静态成员变量,因为静态成员函数中没有this指针,编译器不知道使用的成员变量是哪个对象的变量。

普通成员函数都包含指向具体对象的this指针,哪个对象调用成员函数,this指针就指向这个对象。

系列文章

【二、new与delete详解】

【四、const与this指针详解】详解C与C++中const的异同,类中的const


相关文章
|
7天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
26 4
|
23天前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
23天前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
30天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
1月前
魔法指针 之 指针变量
魔法指针 之 指针变量
15 1
|
1月前
利用指针函数
【10月更文挑战第2天】利用指针函数。
17 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
29 2
|
1月前
|
C++
析构造函数就是为了释放内存,就是在局部指针消失前释放内存,拷贝构造函数就是以构造函数为模块,在堆里面新开一块,同一个变量在堆里面的地址
本文讨论了C++中构造函数和析构函数的作用,特别是它们在管理动态内存分配和释放中的重要性,以及如何正确地实现拷贝构造函数以避免内存泄漏。
37 2
|
1月前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
23 2
|
1月前
|
C语言 C++
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)