C++类与对象学习笔记(1)--访问限定符、作用域、对象的大小、this指针、封装

0.类和对象概述

C语言面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成

1.类和对象的概念

对一组性质相同的事物的描述,包括事物的属性和方法对象类的一个实例
例如,老师是一个类,C++老师就是老师类的一个对象

2.封装的理解

面向对象的三大特性:封装继承多态

  • 1.封装是面向对象程序设计最基本的特性。把数据(属性)函数(方法)合成一个整体,这在计算机世界中是用类和对象实现的(把属性和方法进行封装)
  • 2.把客观事物封装成抽象的类,并且类可以把自己的属性和方法只让可信的类或者对象操作,对不可信的类或对象进行信息的隐藏。(对属性和方法进行访问控制)

3.根据C语言的结构体引入类

C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数

struct stu
{
 //定义变量(数据)
 int num;
 int age;
 //定义函数(方法)
 void Learn()
 {
  cout << "学生正在睡觉" << endl;
 }
};

c++支持用struct定义类,是为了学习者可以方便从C语言过渡。在C++中,定义一个类,更多的使用class

class stu
{
 //定义变量(数据)
 int num;
 int age;
 //定义函数(方法)
 void Learn()
 {
  cout << "学生正在睡觉" << endl;
 }
};

4.类的定义

class ClassName{
	//成员变量
	//成员函数
};

class定义类的关键字ClassName类的名字{}中为类的主体,注意类定义结束时后面分号。类中的元素称为类的成员,类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数
类的两种定义方式:

  • 声明和定义全部放在类体中
class Tearch
{
public:
 char* _name;
 char* _num;
 int age;
public:
 void Sleep()
 {
  cout << "老师正在睡觉" << endl;
 }
};

注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理

  • 声明放在.h文件中,类的定义放在.cpp文件中
//.h中
class stu
{
 char* _name;
 int _num;
 int _age;
 //方法的声明
 void Learn();
};
//.cpp中
void stu::Learn()
{
 cout << "学生正在上课" << endl;
}

注:::是类域限定符,也是命令空间域的限定符,表明你正在定义那个类中的函数。一般情况下,更期望采用第二种方式。

5.类的访问限定符及封装

C++实现封装的方式是用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
访问限定符分为:

  • public公有
  • private私有
  • protected受保护的

分别进行说明:

  • public修饰的成员在类外可以直接被访问
  • protectedprivate修饰的成员在类外不能直接被访问
  • 访问权限作用域从该访问限定符出现的位置开始到下一个访问限定符出现时为止
  • class默认访问权限privatestructpublic(因为struct要兼容C)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

面试题:

  • 如何在类外访问一个类中私有的成员变量?
    我们可以根据类内的公有方法去访问类内私有的成员变量
  • C语言和C++struct的区别?C++structclass区别?
    C中struct里只能存在变量,不能存在方法,而C++中的struct既可以存在变量,也可以存在函数方法。C++中的struct定义的类默认访问权限是public,而class定义的类是private

6.类的作用域

定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用:: 作用域解析符指明成员属于哪个类域
作用域可以分为以下几类:

  • 局部域
  • 全局域
  • 类域
  • 命名空间域
namespace N1
{
 int a = 10;
 void TestFunc()
 {
  cout << "TestFunc" << endl;
 }
}
int a = 20;
class A1
{
public:
 void setA(int a){
  this->a = a;
 }
 void PrintA(){
  cout << a << endl;
 }
private:
 int a;
};
int main()
{
 A1 b;
 b.setA(30);//把类中私有的a设置为30
 b.PrintA();//打印的是30
 cout << N1::a << endl;//打印的是命名空间中的a=10
 cout << a << endl;//打印的是全局域的a=20
 return 0;
}

注意: 尽量避免成员函数的参数成员变量同名成员变量在类中具有全局作用域属性

7.类的实例化

类类型创建对象的过程,称为类的实例化。例如:给你一张建筑图纸(代表类),然后根据图纸修建房子,这个房子就代表对象

注意点:

  • 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
  • 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
class Tearch
{
public:
 char* _name;
 char* _num;
 int age;
public:
 void setVal(char* name,char* num,int _age) {
  _name = name;
  _num = num;
  _age = age;
 }
 void sleep()
 {
  cout << _name << "老师正在睡觉" << endl;
 }
};
int main()
{
 Tearch t;//根据类Tearch实例化对象
 t.setVal("zhangsan", "123", 10);
 t.age = 10;
 t.sleep();
 return 0;
}

8.计算类对象的大小

创建一个对象时的内存布局:只保存成员变量,而成员函数存放在公共的代码段

在这里插入图片描述

所以我们在计算一个对象的大小时,只需要计算包括其成员变量的大小不用考虑成员函数。只计算成员变量的大小和计算结构体大小是一样的,根据内存对齐规则直接去计算即可。

// 类中既有成员变量,又有成员函数,4个字节
class A1
{
public:
 void f1()
 {}
 void f2()
 {}
private:
 int _a;
};
// 类中仅有成员函数,大小为1个字节,代表进行占位,不存储数据,表示对象存在过
class A2
{
public:
 void f1()
 {}
 void f2()
 {}
};
// 类中什么都没有---空类,也是1个字节,为了标识这个类
class A3
{};
//总大小为4的整数倍数既16
class A4
{
	char c1;//0
	int a;//4-7
	char c2;//1
}

结构体内存对齐规则:

  • 第一个成员在与结构体偏移量为0的地址处
  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值,VS中默认的对齐数为8,gcc中的对齐数为4
  • 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

为什么存在内存对齐:

  • 空间换取时间,内存是按整数倍(vs是8个字节)的位置访问的

  • 平台移植原因:不是所有的硬件平台都能访问任意地址的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据内存对齐可以增强程序的可移植性

9.this指针

this指针指向当前对象谁调用它谁就是谁。存储在上,实质是一个形参指针。(widows下vs也可用ecx寄存器传递)

class Date
{
private:
 int _year;
 int _month;
 int _day;
public:
 void Print()
 {
  cout << _year << "-" << _month << "-" << _day << endl;
 }
 void SetDate(int year, int month, int day){
  this->_year = year;
  this->_month = month;
  this->_day = day;
 }
};
int main()
{
 Date d1;
 Date d2;
 d1.SetDate(2018, 9, 2);
 d2.SetDate(2018, 9, 3);
 d1.Print();
 d2.Print();
 return 0;
}

注:成员变量可以显示的加上this,但是成员函数是不能加 this。

class Date
{
private:
 int _year;
 int _month;
 int _day;
public:
 void Print()
 {
  cout << _year << "-" << _month << "-" << _day << endl;
 }
 void SetDate(int year, int month, int day){
  this->_year = year;
  this->_month = month;
  this->_day = day;
 }
    void sleep(){
        cout<<"正在睡觉"<<endl;
    }
};
int main()
{
 //访问printf用到了this,对空指针操作
 Date* pd = NULL;
 pd->Print();
 //sleep函数没用对this指针操作,可以编译通过
 pd->sleep();
}

注:this指针可以为空,调用不使用 this的方法可以,但是调用使用this的方法不行

C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指
针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递编译器自动完成

this指针的特性:

  • this指针的类型:类类型* const
  • 只能在“成员函数”的内部使用
  • 时时刻刻指向当前对象,不属于对象的一部分,不会影响sizeof的结果
  • this指针成员函数第一个隐含的指针形参(存放在栈帧上),一般情况由编译器通过ecx寄存器自动传递不需要用户传递

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值