黑马程序员c++学习笔记 P99--P120

不定期更新

P99 类和对象

  • c++ 面向对象的三大特征:封装、继承、多态

  • 对象:有属性和行为

  • 封装:

    • 封装的意义:
      将属性和行为作为一个整体,表现生活中的事物
      将属性和行为加以权限控制
      太极创客的解释 使类的设计者和使用者分开
    • 语法:class 类名(访问权限:属性/行为);
    • 类和封装内容记到太极创客的笔记中
  • 设计一个圆类,求周长

  • 在这里插入图片描述

P100 类和对象-封装-案例-设计学生类

  • 类中的属性和行为统称为成员。
  • 通过类中的方法给属性赋值

P101 类和对象-封装-访问权限

  • 访问权限

    • public   公共权限
      成员:类内可以访问,类外也可以用。
    • protected 保护权限
      成员:类内可以访问,类外不可以访问。
    • private 私有权限
      成员:类内可以访问,类外不可以访问。

P102 类和对象-封装-c++中class和struct的区别

  • 在c++ 中struct 和 class唯一区别就在于默认的访问权限不同
    在不写public protected private 中的任何一个时。
    struct 里定义的成员默认权限为公共
    class 里定义的成员默认权限为私有

P103 类和对象-封装-成员属性私有化

  • 成员属性私有化的优点
  1. 将所有成员属性设置为私有,可以自己控制读写权限
  2. 对应写权限,我们可以检测数据的有效性

P104 类和对象-封装-设计案例1-立方体类

  • 题目要求
    在这里插入图片描述

  • 写程序时先写注释 边写边理清思路,要做哪些内容

  • 步骤:
    在这里插入图片描述

P105 类和对象-封装-设计案例-点和圆关系

  • 题目要求:根据点到圆心的距离判断点和圆的关系属于哪个(在圆内、外、上、在圆心)

  • 将点设计为一个类

  • 在这里插入图片描述

  • 核心:一个类中可以用另一个类定义一个该类成员

  • 一个类只用一个c 和 h ,在.h 中只写声明,在.c中只写实现。属性在 .h中

P106类和对象-对象特性-构造函数和析构函数

  • 对象的初始化和清理

    • 定义是初始化(构造函数),用完清理(析构函数)

    • 在这里插入图片描述

    • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。

    • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

  • 构造函数语法:类名 (){}

    • 构造函数没有返回值也不写void
    • 函数名与类名相同
    • 构造函数可以有参数,因此可以发生重载
    • 程序在调用对象时会自动调用构造,无需手动调用,而且只会调用一次
  • 析构函数语法:~ 类名(){}

    • 析构函数没有返回值也不写void
    • 函数名与类名相同,且在名称前加~
    • 构造函数不可以有参数,因此不可以发生重载
    • 程序在调用对象时会自动调用析构,无需手动调用,而且只会调用一次

P107 类和对象-对象特性-构造函数的分类及调用

  • 两种分类方式

    • 按参数分为:有参构造和无参构造
    • 按类型分为:普通构造和拷贝构造
    • 下图是三种类型写法
    • 在这里插入图片描述
  • 三种调用方式:

    • 括号法
    • 显示法
    • 隐士转换法
  • 括号法调用(无参和有参和拷贝)如下图
    在这里插入图片描述

    • 注意事项:调用默认构造函数时不要加();Person P1(); 因为编译器会认为是在函数声明
  • 显示法
    在这里插入图片描述

    • Persion();//此句为匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象

    • 注意事项:不要利用拷贝构造函数 初始化匿名对象,如图
      在这里插入图片描述

    • 隐式法
      在这里插入图片描述

P108 类和对象-对象特性-拷贝构造函数

  • 什么时候需要调用拷贝构造函数
    • 使用一个已经创建完毕的对象来初始化一个新的对象

    • 如下图用创建好的p1初始化p2
      在这里插入图片描述

    • 值传递的方式给函数参数传值
      在这里插入图片描述

    • 以值方式返回局部对象

    • 下图63行return并不是返回62行创建的p1 而是复制一份p1把复制出来的返回

    • 在这里插入图片描述

P109 构造函数调用规则

  • 默认情况下,c++编译器至少给一个类添加3个函数
    • 默认构造函数(无参,函数体为空);
    • 默认析构函数(无参,函数体为空);
    • 默认拷贝构造函数,对属性进行值拷贝;
  • 构造函数调用规则如下
    • 如果用户定义有参构造函数,c++不再提供默认无参构造函数,但是会提供默认拷贝构造
    • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数(默认构造和有参构造都没有)
  • test01 函数执行完之后 会执行p和p1 的析构函数,先进后出所以先执行p1的析构
    在这里插入图片描述
  • 即使不写拷贝构造,也会有一个默认拷贝构造(值拷贝),即不写拷贝构造函数,上图p2 年龄也是18

P110 类和对象-对象特性-深拷贝与浅拷贝

  • 浅拷贝:简单的复制拷贝操作(编译器的拷贝 )

  • 深拷贝:在堆区重新申请空间,进行拷贝操作

  • 总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

  • 如下图:p2拷贝p1 来的,体重的指针见下2图,拷贝时p2 p1 中的体重指针是堆区的同一个位置,p2 析构先执行释放掉内存后,p1的析构执行时会出现堆区内存重复释放的问题,所以就崩了

  • 在这里插入图片描述

  • person 构造和析构
    在这里插入图片描述

  • 如何解决浅拷贝带来的这个问题

    • 浅拷贝的问题要利用深拷贝来操作
    • 在新建p2时重新分配给p2.体重指针一个和p1 不同的空间
    • 在这里插入图片描述

P111类和对象-对象特性-初始化列表

  • 作用:c++提供了初始化列表语法,用来初始化属性
  • 语法:构造函数():属性1(值1),属性2(值2)…{ }
  • 传统初始化操作是由有参构造函数
  • 示例:
    在这里插入图片描述

在这里插入图片描述

  • 完整示例:注意:位置

在这里插入图片描述

P112类和对象-对象特性-类对象作为类成员

  • c++ 类中的成员可以是另一个类的对象,我们程该成员为对象成员
  • 例如:
    class A{};
    class B
    {
    A a;
    }
  • B 类中有对象 A 作为成员,A 为对象成员。那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
  • 结论:先构造成员对象,在构建自身B. 析构的顺序是相反的

缺的第30 静态成员

  • 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
  • 静态成员分为:
    • 静态成员变量

      • 所有对象共享同一份数据
      • 在编译阶段就已经分配好内存(全局区)
      • 类内声明,类外初始化(必须得有初始值)

      在这里插入图片描述

      • 第二个输出还是200

      +

    • 静态成成员函数

      • 所有对象共享同一个函数
      • 静态成员函数只能访问静态变量
    • 静态成员变量不属于某个对象,所有对象都共享同一份数据,因此静态成员变量有两种访问方式

      • 通过对象进行访问
      • 通过类名进行访问

      在这里插入图片描述

    • 静态成员变量也是有访问权限的

      • 类外访问不到私有静态变量

P113 类和对象-对象特性-静态成员函数

  • 所有对象公用一个函数
  • 静态成员函数只能访问静态成员变量

在这里插入图片描述

  • 静态成员函数访问方式
    • 通过类名
    • 通过对象
    • 静态成员函数也有访问权限

P114 成员变量和成员函数分开存储

  • c++对象模型和this指针
    • 成员变量和成员函数分开存储
    • 在c++ 中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上
  • 空对象占用的内存空间
  • 在这里插入图片描述

P115 类和对象-对象特性-this指针的用途

  • 由上节的内容可以知道,每一个非静态成员函数只会诞生一份函数示例,也就是说多个同类型的对象会公用一块代码,那么问题是这一块代码如何区分哪个对象调用自己的呢?

  • c++通过提供特殊的对象指针,this指针,解决上述问题,this指针指向被调用的成员函数所属的对象

  • this指针是隐含在每一个非静态成员函数内的一种指针,不需要定义,直接使用即可

  • this指针的用途

    • 当形参和成员变量同名时,可用this指针来区分(解决名称冲突)
    • 如下图,不加this -> 输出是乱码,因为外边传进来的age 和 类内的age 同名,这样可能编译器不会报错但是有问题。加一个this->,就是说等号左边的age是类内的,就区分开了。

    在这里插入图片描述

    • 在类的非静态成员函数中返回对象本身,可使用return * this

    在这里插入图片描述

    • 返回值用值返回而不用引用的效果,值返回返回的是一个新的复制出来的对象,不会改变原来的对象,新复制出来的不是复制里面加完的等于20的,而是复制的初始的所以age始终是10,加完就是20 不确定这儿理解的对不对

    在这里插入图片描述

  • 链式编程思想

P116 类和对象-对象特性-空指针访问成员函数

  • c++中空指针也可以调用成员函数的,但是也要注意有没有用到this指针,如果用到this指针,需要加以判断保证代码健壮性
  • 下图中if判断传进来的是空就不执行,避免程序崩掉

在这里插入图片描述

P117 类和对象-对象特性-const修饰成员函数

  • 常函数:
    • 成员函数后加const后我们称为这个函数为常函数
    • 常函数内不可以修改成员属性
    • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
  • 常对象:
    • 声明对象前加const称该对象为常对象
    • 常对象只能调用自己的常函数,不能掉其他的普通成员函数
  • 示例:
  • this指针的本质是一个指针常量,指针的指向不可以修改
  • 下图代码中相当于Person * const this; 想让this指向的值也不可以修改就要在前面加const
    实际加的位置是 在这里插入图片描述

P118 类和对象-友元-全局函数做友元

  • 生活中你的家有客厅 (Public),有你的卧室(Private)客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去但是呢,你也可以允许你的好闺蜜好基友进去。在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
  • 友元的目的就是让一个函数或者类 访问另一个类中私有成员
  • 友元的关键字为 friend
  • 友元的三种实现
    • 全局函数做友元
    • 类做友元
    • 成员函数做友元
  • 全局函数做友元
  • 语法:

在这里插入图片描述

P119 类和对象-友元-友元类

  • 一个知识点:类内写类的构造函数声明,类外写实现

在这里插入图片描述

class Building;
class goodGay
{
public:
	goodGay();
	void visit();
private:
	Building *building;
};

class Building
{
	//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
	friend class goodGay;
public:
	Building();
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom;//卧室
};
Building::Building()
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
	building = new Building;
}
void goodGay::visit()
{
	cout << "好基友正在访问" << building->m_SittingRoom << endl;
	cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void test01()
{
	goodGay gg;
	gg.visit();
}
int main(){
	test01();
	system("pause");
	return 0;
}

P120 类和对象-友元-成员函数做友元

在这里插入图片描述

class Building;
class goodGay
{
public:

	goodGay();
	void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
	void visit2(); 

private:
	Building *building;
};


class Building
{
	//告诉编译器  goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容
	friend void goodGay::visit();
public:
	Building();
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom;//卧室
};
Building::Building()
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
	building = new Building;
}
void goodGay::visit()
{
	cout << "好基友正在访问" << building->m_SittingRoom << endl;
	cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void goodGay::visit2()
{
	cout << "好基友正在访问" << building->m_SittingRoom << endl;
	//cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void test01()
{
	goodGay  gg;
	gg.visit();

}
int main(){
	test01();
	system("pause");
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值