C++梁哥笔记day9 | 我的日常分享

C++梁哥笔记day9

类与对象

一、(续day8)静态成员变量详解

  • 静态成员函数的引出
    在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是不能访问普通成员变量。静态成员函数的意义,不在于信息共享、数据沟通,而在于管理静态数据成员,完成静态数据成员的封装。
    静态成员函数只能访问静态成员变量,不能访问普通成员变量,静态成员函数的使用和静态成员变量一样,静态成员函数也有访问权限,普通成员函数可访问静态成员变量、也可以访问非静态成员变量。但是普通成员函数是依赖对象的,必须有对象后才能使用,但是对于私有静态成员通常我们不想通过创建对象后再调用方法使用、如果类没有实例化对象,难道就不能使用data了吗,解决这些问题就要用到静态成员函数。
  • 静态成员函数

1、静态成员函数 属于类 可以通过类名称直接访问.

2、也可以通过对象名来访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Data
{
private:
int num;//普通成员变量
static int data;//静态成员变量
public:
Data() {}
int getData(){
return data;
}
//静态成员函数
static int getStaticData(){
return data;
}
};
int Data::data = 100;
void test01(){
//cout<<"data:"<<Data::data<<endl;//error: 'int Data::data' is private
//cout<<"data:"<<Data::getData()<<endl;//error: cannot call member function 'int Data::getData()' without object
cout<<"data:"<<Data::getStaticData()<<endl;
}

运行结果:
图片

注意:
1、静态成员函数,存在的意义就是操作静态成员
2、静态成员函数不能访问普通成员变量
3、普通成员函数,既可以访问普通成员函数,也可以访问静态成员函数。

  • const修饰静态成员变量
    如果一个类的成员,既要实现共享,又要实现不可改变,那就static const修饰。定义静态const数据成员时,最好在类内部初始化,类外定义要加const
1
2
3
4
5
6
7
class Data{
public:
static const int num1;
const static int num2;
const static int num3 = 30;
};
const static int Data::num2 = 20;

练习:静态成员变量统计当前对象个数。

  • 单例模式设计(重要)
    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只用一个实例而且该实例易于外界访问。从而方便对实例个数的控制并节约系统资源。如果在系统中某个类的对象只能存在一个,单例模式是最好的方案。
    图片

Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝函数拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

用单例模式,模拟公司员工使用打印机场景,打印机可以打印员工要输入的内容,并且可以累积打印机的使用次数。

步骤一:在单例类内部定义一个Singleton类型的静态对象,作为外部共享的唯一实例
步骤二:提供一个静态方法,让客户可以访问它的唯一实例。
步骤三:为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Data
{
private:
int num;//普通成员变量
static int data;//静态成员变量
public:
Data() {}
int getData(){
return data;
}
//静态成员函数
static int getStaticData(){
return data;
}
};
int Data::data = 100;
void test01(){
//cout<<"data:"<<Data::data<<endl;//error: 'int Data::data' is private
//cout<<"data:"<<Data::getData()<<endl;//error: cannot call member function 'int Data::getData()' without object
cout<<"data:"<<Data::getStaticData()<<endl;
}
class Printer{
private:
//1.定义一个静态的对象指针变量 保存唯一实例
static Printer * singlePrint;
public:
//2.提供一个方法获得单例指针
static Printer * getSinglePrint(){
return singlePrint;
}
//3.防止该类实例化其他对象 将类构造方法 全部私有化
private:
Printer(){count = 0;}
Printer(const Printer &ob){}
public:
//4.设置功能函数(自定义)
void printText(char *str){
cout<<"打印"<<str<<endl;
count++;
}
int count;
};
Printer *Printer::singlePrint = new Printer;//这个定义相当于在类中 可以调用私有的默认构造方法 实例化对象不会报错
int main(){
//打印任务1
Printer *p1 = Printer::getSinglePrint();
p1->printText("打印任务1-1");
p1->printText("打印任务1-2");

//打印任务2
Printer *p2 = Printer::getSinglePrint();
p2->printText("打印任务2-1");
p2->printText("打印任务2-2");
(*p2).printText("打印任务2-3");

cout<<"打印任务个数"<<p1->count<<endl;
cout<<"打印任务个数"<<p2->count<<endl;
return 0;
}

运行结果:
图片


二、C++面向对象模型初探

  • 成员变量和函数的存储
    在C语言中,“分开来声明的,也就是说,语言本省并没有支持‘数据’和‘函数’之间的关联性,我们把这种程序方法称为‘程序性的’,由一组分布在各个以功能为导航的函数中”的算法驱动,他们处理的是共同的外部数据。
    C++实现了“封装”,那么数据(成员属性)和操作(成员函数)是什么样的呢?“数据”和“数理数据的操作(函数)”是分开存储的。C++中的非静态成员直接内含在类对象中,就像C中的struct一样。成员函数虽然内含在class声明之内,却不出现在对象中。每一个非内联成员函数只会诞生一份函数实例。
    总结:C++将数据和方法封装在一起,但是数据和方法是分开存储的,每个对象拥有独立的数据,每个对象共享同一个方法。

  • this指针

图片
哪个对象调用方法,那么方法中的this就指向哪个对象。

  • this指针的注意点

    1. this指针是隐含在对象成员函数内的一种指针

    2. 成员函数通过this指针即可知道操作的是哪个对象的数据

    3. 静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量
      (静态成员函数属于类,函数内部没有this指针,无法判断操作的是哪个对象,所以不能操作)

      模拟this指针:
      图片

  • this的应用

    1. 当形参和成员变量同名时,可以用this指针来区分

      1
      2
      3
      void setNum(int num){
      this->num = num;
      }
    2. 在类的非静态成员函数中返回对象本身,可以使用return *this;

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class MyCout
      {
      public:
      MyCout& mycout(char *str){
      cout<<str;
      return *this;
      }
      };
      void test02(){
      MyCout ob;
      ob.mycout("haha").mycout("heihei").mycout("xixi");
      }

      运行结果:
      图片