【C++】封装,this指针
目录
一、封装的概念
1、实现封装的关键
访问修饰符
将数据成员私有化
隐藏实现细节
2、成员数据
3、成员函数
二、this指针
1、对象模型
各对象完全独立的安排内存的方案
各对象的代码区共用的方案
2、 对象模型与 this 指针
this 指针
this指针目的:
一、封装的概念
封装是C++面向对象编程的三大特性之一(封装、继承、多态),它将数据和操作数据的方法捆绑在一起,形成一个独立的单元(类)。通过访问控制修饰符(public
、private
、protected
),封装可以隐藏内部实现细节,仅暴露必要的接口,提高代码的安全性和可维护性。
1、实现封装的关键
访问修饰符
class Example {
private:int hiddenData; // 外部无法直接访问
public:void setData(int value) { hiddenData = value; } // 通过公有方法间接修改私有成员int getData() { return hiddenData; }
};//最后的;必不可少,所有说明都有分号
其中”class 类名” 称为类头(class head)。花括号中的部分称为类体(class body),类体中定义了类成员表(class memberlist)。
在C++中,类是一种数据类型(设计一个类型,定义一种对象)。 客观事物是复杂的,要描述它必须从多方面进行,也就是用不同的数据类型来描述不同的方面。如商场中的商品可以这样描述:
商品名称(用字符串描述),该商品数量(用整型数描述)该商品单价(用浮点数描述),该商品总价(用浮点数描述)。
这里用了属于三种不同数据类型,四个数据成员(data member)来描述一种商品。
private
:成员仅在类内部可访问,外部无法直接修改。protected
:成员在类及其派生类中可访问。public
:成员对外完全开放,提供类与外界的交互接口。
将数据成员私有化
将类中的关键数据声明为private
,避免外部直接修改导致数据不一致。通过公有成员函数(如getter
和setter
)提供可控的访问和修改途径。
class BankAccount {
private:double balance;
public:void deposit(double amount) {if (amount > 0) balance += amount;}double getBalance() { return balance; }
};
隐藏实现细节
类的内部逻辑(如算法、数据结构)可以隐藏在私有成员函数中,仅暴露必要的功能接口。例如,使用私有方法处理数据验证:
class User {
private:bool isValidPassword(const string& pwd) { /* 密码复杂度验证逻辑 */ }
public:void setPassword(const string& pwd) {if (isValidPassword(pwd)) /* 存储密码 */;}
};
2、成员数据
class CGoods{ // class
private:char Name[20];int Amount;float Price;float Total;
};//sizeof=32,最后的分号不可少,这是一条说明语句
关键字 class 是数据类型说明符,指出下面说明的是类型。标识符 CGoods是商品这个类的类型
名。花括号中是构成类体的一系列的成员,关键字 public 是一种访问限定符。
访问限定符(access specifier)有三种:public(公共的),private (私有的)和protected(保护的)。如果不写访问限定符,class默认私有,struct默认公有。第一种说明的成员能从外部进行访问,另外两种说明的成员不能从外部进行访问(可以去访问这个类型所设计的公有成员,但是不是对类型的公有成员进行访问,而是对这个类型所产生的对象去访问)。每种说明符可在类体中使用多次。它们的作用域是从该说明符出现开始到下一个说明符之前或类体结束之前结束。
如果在类体起始点无访问说明符,系统默认定义为私有(private)。访问说明符 private(私有的)和 protected(保护的)体现了类具有封装性(Encapsulation)。
类和对象的区别:
- 概念区别
类是C++中的一种用户自定义数据类型,用于描述一组具有相同属性和行为的对象的抽象模板。类定义了对象的属性和方法,但不占用实际内存空间。
对象是类的实例,是具体存在的实体,占用内存空间。对象通过类来创建,具有类定义的属性和行为。
- 定义方式
类通过
class
或struct
关键字定义,包含成员变量和成员函数:class Person { public:string name; // 成员变量void sayHello() { // 成员函数cout << "Hello, " << name << endl;} };
对象通过类名声明并初始化:
Person p1; // 创建Person类的对象p1 p1.name = "Alice"; p1.sayHello();
- 内存分配
类作为模板,本身不占用内存空间。对象作为实例化结果,根据类定义的成员变量分配实际内存。
- 访问控制
类通过访问修饰符(
public
、private
、protected
)控制成员的访问权限。对象只能访问类中声明为public
的成员。
- 生命周期
类的定义在程序编译时确定,存在于整个程序运行期间。对象的生命周期从创建开始,到销毁结束,可以是局部、全局或动态分配。
- 关系
类是对象的蓝图,对象是类的具体表现。一个类可以创建多个对象,每个对象独立存储数据但共享类的方法定义。
3、成员函数
类型设计的更关键部分是对数据成员的操作,用函数来完成:函数就是方法,方法就是函数
class CGoods{ // class
private:char Name[20];int Amount;float Price;float Total;
public://输入数据void RegisterGoods(const char* name, int amount, float price) {assert(nullptr != name);strcpy(Name, name);Amount = amount;Price = price;Total = Amount * Price;}//计算商品总价值void CountTotal() {Total = Amount * Price;}//读取商品名void GetName(char* name) {assert(nullptr != name);strcpy(name,Name);}//读取商品数量int GetAmount() {return Amount;}//读取商品单价float GetPrice() {return Price;}//读取商品总价值float GetTotal() {return Total;}
};
设计一个类型时,将属性设置为私有,将方法设置为公有(方法只有声明没有实现)。
这样在类中引进了成员函数(member function)或函数成员,也就是函数也成了数据(类)中的一员。类把数据(事物的属性)和函数(事物的行为-操作)封装为一个整体。(封装代表两种含义:一是将数据和方法封装成一个整体,二是在封装过程中将某些属性和某些方法设计成私有的,将某些方法设计成共有的)
四个数据成员被说明成私有,而六个函数成员被说明成公有;这就是说如果从外部对四个数据成员进行操作的话,只能通过六个公有函数来完成,数据受到了良好的保护,不易受外部环境的影响。公有函数集定义了类的接口(interface)。
类是一种数据类型,定义时系统不为类分配存储空间,即使在编译链接过程中也不会给类分配空间,我们只是给对象分配空间,所以不能对类的数据成员初始化。类中的任何数据成员也不能使用关键字extern、auto或register限定其存储类型。
成员函数可以直接使用类定义中的任一成员,可以处理数据成员,也可调用函数成员。成员函数的定义:
前面只对成员函数作了一个声明(函数的原型),并没有对函数进行定义。函数定义通常在类的说明之后进行,其格式如下:
回值类型类名::函数名(参数表);
其中运算符“::”称为作用域解析运算符(scope resolution operator),它指出该函数是属于哪一个类的成员函数。
void CGoods::RegisterGoods(const char*name,int amount,float price){
strcpy(Name,name);//字符串拷贝函数
Amount =amount;
Price =price;
}
写成员函数时,函数的方法名,参数列表,返回值类型必须相同才能作为类的成员函数使用。
二、this指针
1、对象模型
各对象完全独立的安排内存的方案
系统为每一个对象分配了全套的内存,包括安放成员数据的数据区和安放成员函数的代码区。但是区别同一个类所实例化的对象,是由属性(数据成员)的值决定,不同对象的数据成员的内容是不一样的;而行为(操作)是用函数来描述的,这些操作的代码对所有的对象都是一样的。
各对象的代码区共用的方案
仅为每个对象分配一个数据区,代码区(放成员函数的区域)为各对象类共用。
2、 对象模型与 this 指针
对象内存模型:仅针对每个对象的数据成员分配内存空间,而成员函数则由所有对象共享使用。(仅为每个对象的数据分配区域 ,函数为各个对象公用)
- 对象存储非静态数据成员,成员函数通过代码区共享只读。
- 静态成员(数据/函数)不属于对象,存储在数据区。
this 指针
概念:区分是哪个对象调用的函数
编译器对程序员自己设计的类型进行编译时,分三次编译:
1.识别记录类中属性的名称,类型 访问限定,与属性在类中的位置无关
2.识别记录类中函数原型(返回类型+函数名+参数列表), 形参默认值,访问限定 virtual,不识别函数体
3.改写类中定义函数参数列表和函数体,改写对象调用成员函数的形式;
- 隐式参数,指向当前对象地址。
- 编译器自动将成员函数改写为 成员函数(类名* const this, ...)。
this指针目的:
- 1.节省空间
- 2.区分函数调用对象,this指针存放在函数调用中
- 3.(c++中)通过寄存器传递(ECX)不允许修改指向
- 限制:不能用于 static 成员函数(无 this 指针)。
- 空类大小:至少 1 字节,用于标识对象存在。