不定期更新
P99 类和对象
-
c++ 面向对象的三大特征:封装、继承、多态
-
对象:有属性和行为
-
封装:
- 封装的意义:
将属性和行为作为一个整体,表现生活中的事物
将属性和行为加以权限控制
太极创客的解释 使类的设计者和使用者分开 - 语法:class 类名(访问权限:属性/行为);
- 类和封装内容记到太极创客的笔记中
- 封装的意义:
-
设计一个圆类,求周长
-
P100 类和对象-封装-案例-设计学生类
- 类中的属性和行为统称为成员。
- 通过类中的方法给属性赋值
P101 类和对象-封装-访问权限
-
访问权限
- public 公共权限
成员:类内可以访问,类外也可以用。 - protected 保护权限
成员:类内可以访问,类外不可以访问。 - private 私有权限
成员:类内可以访问,类外不可以访问。
- public 公共权限
P102 类和对象-封装-c++中class和struct的区别
- 在c++ 中struct 和 class唯一区别就在于默认的访问权限不同
在不写public protected private 中的任何一个时。
struct 里定义的成员默认权限为公共
class 里定义的成员默认权限为私有
P103 类和对象-封装-成员属性私有化
- 成员属性私有化的优点
- 将所有成员属性设置为私有,可以自己控制读写权限
- 对应写权限,我们可以检测数据的有效性
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;
}