C++从0到1-黑马程序员 课程学习笔记
课程链接: 16 类和对象-封装-属性和行为作为整体_哔哩哔哩_bilibili
C++ 面向对象三大特性 封装 继承 多态
C++认为万事万物皆为对象,对象有其属性和行为
1. 封装
1.1. 封装的意义
(1) 将属性和行为作为一个整体,表现生活中的事物
类中的属性和行为 统一称为 成员
- 属性 成员属性 成员变量
- 行为 成员函数 成员方法
(2) 将属性和行为加以权限控制
类在设计时,可以把属性和行为放在不同的权限下加以控制
访问权限有三种:
- public 公共权限 成员在类内可以访问,类外也可以访问
- protected 保护权限 成员在类内可以访问,类外不可以访问 子类可以访问父类的保护内容
- private 私有权限 成员在类内可以访问,类外不可以访问 子类不可以访问父类的私有内容
const double PI = 3.14
// 设计一个圆类 求圆的周长
// 圆求周长的公式 2 * PI * 半径
class Circle
{
// 权限
public:
// 属性
int m_r;
// 行为
double caclulateZC()
{
return 2*PI*m_r;
}
}
int main()
{
// 通过圆类 创建具体的圆 实例化
Circle cl;
// 给圆对象的属性进行赋值
cl.m_r = 10;
cout << "圆的周长为: " << cl.calculate() << endl;
}
1.2 Class与Struct的区别
唯一的区别:默认的访问权限不同
-
- struct 默认权限是公开 public
- class 默认权限是私有 private
1.3 成员属性私有化
好处: 可以自己控制读写权限
对于写可以检查数据的有效性
2. 对象的初始化和清理
2.1 构造函数和析构函数
C++利用构造函数和析构函数解决对象的初始化和清理问题,这两个函数被编译器自动调用。
对象初始化和清理工作是编译器强制我们做的事情,如果程序员不提供构造函数与析构函数,编译器会提供。
编译器提供的构造函数和析构函数是空实现。
构造函数: 主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用;
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
构造函数语法: 类名(){}
- 没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时会自动调用构造函数,无须手动调用且只会调用一次
析构函数语法: ~类名(){}
- 没有返回值也不写void
- 函数名称与类名相同,在名称前加符号“~”
- 构造函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构函数,无须手动调用且只会调用一次
class Person
{
public:
Person()
{
cout << "构造函数" << endl;
}
~Person()
{
cout << "析构函数" << endl;
}
}
void test()
{
Person p; // 局部变量 栈区 test执行完成后,释放该对象
}
int main()
{
// test();
Person p; // main函数执行完成后,进行析构
system("pause");
return 0;
}
2.2 构造函数的分类以及调用
两种分类方式:
- 按参数分类:有参构造和无参构造(默认构造)
- 按类型分类:普通构造和拷贝构造
三种调用方法:
- 括号法 调用默认构造函数时,不要加(),加入(),编译器会认为是一个函数的声明
- 显示法 不要用拷贝构造函数初始化匿名对象,编译器会认为是一个对象声明
- 隐式转换法
class Person
{
public:
// 拷贝构造函数
Person(const Person &p)
{
// 将传入的对象所有属性,拷贝到该类
age = p.age;
}
}
int main()
{
// 调用方法
// 括号法
Person p1; // 默认构造函数、
// Person p1(); // 错误,编译器会认为是一个函数声明,不会认为是在创建对象
Person p2(10); // 有参构造函数
Person p3(p2); // 拷贝构造函数
// 显示法
Person p1;
Person p2 = Person(10);
Person p3 = Person(p2);
Person(10); // 匿名对象 当前行执行结束后,系统会立即回收掉匿名对象
Person(p3); // 编译器会认为是一个对象声明 Person (p3) 等价于 Person p3
// 隐式构造法
Person p4 = 10; // 相当于Person p4 = Person(10);
Person p5 = p4;
return 0;
}
2.3 拷贝构造函数调用时机
拷贝构造函数使用场景:
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数传递参数
- 值方式返回局部对象
// 使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
Person p1(20);
Person p2(p1);
}
// 值传递的方式给函数传递参数
void doWork(Person p){
}
void test02(Person p)
{
Person p;
doWork(p);
}
// 值方式返回局部对象
Person doWork2()
{
Person p1;
return p1;
}
void test03()
{
Person p = doWork2(); // doWork2中的p1与p不是同一个对象
}
2.4 构造函数调用规则
默认情况下,C++编译器至少给一个类添加三个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
- 若用户定义有参构造函数,C++不再提供默认无参构造,但会提供默认拷贝构造函数
- 若用户定义拷贝构造函数,C++不会再提供其他构造函数
2.5 深拷贝和浅拷贝
❗若属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
分类 | 释义 | 备注 |
---|---|---|
浅拷贝 | 简单的赋值拷贝操作 | 编译器提供的拷贝构造函数,是浅拷贝操作,会造成堆取内存重复释放 |
深拷贝 | 在堆区重新申请空间,进行拷贝操作 |
class Person
{
public:
Person(){
cout << "默认构造函数" << endl;
}
Person(int age, int height){
m_Age = age;
m_Height = new int(height); // 将数据创建到了堆区
cout << "有参构造函数" << endl;
}
Person(const Person &p){
cout << "拷贝构造函数" << endl;
m_Age = p.m_Age;
// m_height = p.m_height; // 编译器提供拷贝函数实现就是这行代码,浅拷贝,会造成内存的重复释放 -》 报错
// 深拷贝
m_Height = new int(*p.m_Height);
}
~Person(){
// 析构代码 将堆区开辟数据进行释放
if ( m_Height != NULL)
{
delete m_Height;
m_Height = NULL; // 避免野指针
}
cout << "析构函数" << endl;
}
private:
int m_Age;
int *m_Height;
};
void test01()
{
Person p1(18,160);
Person p2(p1);
}
2.6 初始化列表
语法:构造函数(): 属性1(值1), 属性2(值2),...{}
2.7 类对象作为类成员
C++类中成员可以是另一个累的对象,我们称该成员为对象成员
当其他类对象作为本类成员,构造时先构造类对象,再构造本身,析构顺序与构造相反
class Phone
{
public:
Phone(string pName)
{
m_PName = pName;
cout << "Phone 构造函数" << endl;
}
string m_PName;
};
class Person
{
public:
Person(string name, string pName):m_Name(name),m_Phone(pName)\
{
cout << "Person 构造函数" << endl;
}
string m_Name;
Phone m_Phone;
};
void test01()
{
Person p("张三","苹果");
}
2.8 静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量,不能访问非静态成员变量
静态成员变量不属于某个对象,所有对象都共享同一份数据,因此静态成员变量有两种访问方式:
- 通过对象进行访问
- 通过类名进行访问
静态成员变量也有访问权限.
// 静态成员变量
class Person
{
public:
static int m_A;
};
int Person::m_A = 100;
void test01()
{
Person p;
cout << p.m_A << endl;
Person p2;
p2.m_A = 200;
cout << p.m_A << endl; // 输出为200,因为静态成员变量共享同一份数据
}
void test02()
{
// 静态成员变量不属于某个对象,所有对象都共享同一份数据,因此静态成员变量有两种访问方式:
// 通过对象进行访问
Person p;
cout << p.m_A << endl;
// 通过类名进行访问
cout << Person::m_A << endl;
}
int main()
{
// test01();
test02();
return 0;
}
标签:函数,Person,对象,成员,C++,程序员,拷贝,黑马,构造函数
From: https://blog.csdn.net/rabbit_qi/article/details/136943335