【三、类中的静态成员】静态成员变量与静态成员函数(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


相关文章
|
13天前
|
存储 安全 编译器
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
36 5
|
14天前
|
编译器 C++
函数指针和函数对象不是同一类型怎么替换
函数指针和函数对象不是同一类型,为何可替换用作同一函数的参数
|
14天前
|
Java
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
20 3
|
14天前
|
存储 C语言
C语言的函数返回值和指针
C|函数返回值(区分各类值)和指针(区分各类存储空间)的细节
|
14天前
|
存储 Java C#
C++语言模板类对原生指针的封装与模拟
C++|智能指针的智能性和指针性:模板类对原生指针的封装与模拟
|
12天前
|
C++
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
13 0
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
|
14天前
|
C语言
【C语言】:详解函数指针变量,函数指针数组及转移表
【C语言】:详解函数指针变量,函数指针数组及转移表
17 2
|
10天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
14 0
|
11天前
|
C语言
C语言中的函数指针、指针函数与函数回调
C语言中的函数指针、指针函数与函数回调
7 0
|
14天前
|
C语言
【C语言】:深入理解指针变量
【C语言】:深入理解指针变量
8 0