简介
本课程将代领小伙伴们真正迈入C++语言的面向对象大门,在课程中,将会深入讲解类的定义方法,属性的封装方法,构造函数和析构函数等内容,并且所有知识均会通过编码实践的方式讲解到操作层面,力求帮助小伙伴们即学即会!
第1章 课程介绍
第2章 类与对象初体验
2-1 C++类和对象(04:27)
“类”和“对象”,它们呢是我们封装篇大戏中的领衔主演,不过咱们的“类”呢是抽象派,玩的呢就是概念,“对象”呢则真实而具体。那么有了主角之后呢,我们还是需要一些配角帮衬着剧情才够热闹,所以呢我们下面隆重为大家介绍各位配角。
配角:
- “数据成员和成员函数”:它们构成了精彩而完整的“类”。
- “构造函数和析构函数”:它们呢描述了“对象”的生生死死。
- “对象的复制与赋值”:使“类”的定义充满艺术。
- “对象的数组与对象指针”:将应用形态发挥得淋漓尽致。
- “this指针”:它贯穿于我们这部大戏的始终却很少崭露头角,它的加入使“类”与“对象”得以有机结合,更是为封装篇画龙点睛。
大家学完了这些之后相信大家的思维模式呢就逐步地从面向过程转向面向对象。
堆和栈的区别
栈:程序每调用一个函数后,建立一个新的栈帧空间保存当前调用函数中的所有局部变量,也就是说每个函数里面的变量都是在这个函数的栈帧内,
堆:程序运行过程中,向操作系统(OS)申请的系统内存(Mem),系统返回堆空间的地址。
栈帧:变量的所在地 ,变量可直接存取数值。
- 堆: 向系统申请的内存空间,通过函数内的指针变量,赋值指针申请内存返回的地址,用于存取堆空间里的数据。
不同之处:
栈帧:在函数结束时会自动释放,
堆: 需要主动申请释放,或者等程序运行结束后。
操作系统会自动释放程序运行期间申请的内存空间。
所谓变量,在经过编译器,编译、链接之后,是直接的内存地址。计算机直接对内存地址存取数据。
2-2 C++类对象的定义(11:56)
实例化对象
从栈实例化对象
从堆实例化对象
栈用.
去访问对象成员,而堆则是用->
来访问对象成员。
第3章 初始字符串类型
3-1 C++ 初始String(13:51)
getline(cin,name);//获取字符串,可以是空格,换行符,cin获取时不能为换行符。
常见的字符串数组操作函数
- strlen:
- strstr:
- strcat:
- strcpy:
- strcmp:
- strncpy:
- strncmp:
string类型
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name = "hejian"; //赋值1
string hobby("basketball"); //赋值2
string s1(name); //复制1
string s2 = name; //复制2
int n = 3;
char ch = 'd';
string s3(n, ch); //ch只能是char型,不能是string型
string s4 = "hello" + name;
string s5 = "hello" + name + "master";
//string s6 = "hello" + "master"; //错误
cout << name << endl;
cout << hobby << endl;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
return 0;
}
第4章 属性封装的艺术
4-1 C++属性封装之初始封装…(05:30)
封装的好处,能对传入的参数做到条件限制的作用.
面向对象的指导思想就是以对象为中心,就是要以谁做什么来表达代码的逻辑。从代码来看就是要将所有的数据操作转化为成员函数(方法)的调用,换句话说,对象在程序中所有行为都通过调用自己的函数来完成。
private为私有成员,只读属性,无法被外界所修改
第5章 精彩的类外定义
5-1 类外定义(05:56)
类内定义:在定义一个类的时候将成员函数的函数体写在类的内部
类内定义的成员函数,编译器会将其优先编译为内联函数(不会以inline的形式写出来,但会以inline的方式优先编译)
内联函数:inline编译时,代码替换。
类外定义:
1.同文件类外定义(成员函数定义在类的外部,但其定义与类的定义在同一个文件当中)
2.分文件类外定义
.h和.cpp类外定义
在头文件中声明所有的数据成员和成员函数,.cpp中对成员函数进行定义。
第6章 对象的生离死别
6-1 C++ 构造函数讲解(08:26)
构造函数是为了避免多次初始化或者忘记初始化的情况,它仅被调用一次。
与类名同名,没有返回值,名称与类名相同。可以重载
当用户没有定义构造函数时,编译器自动生成一个构造函数
其实就是在类定义的时候,在类中建立一个和类名相同的函数,附一些初值,这样在实例化类的时候,就会默认的给实例化的对象给这些初值。
实例化之后才会占用内存空间,代码是存储在代码区公用的。
构造函数的规则和特点
1.与类同名
2.没有返回值,void也不用写
3.可以有多个重载形式,要遵循重载函数的规则
4.即使有多个构造函数也仅用到一个构造函数
5.当用户没有定义构造函数时,编译器自动生成一个构造函数
内存分区
栈区:int x=0;int p=NULL;
堆区:int p=new int[20];
全局区:存储全局变量及静态变量
常量区:string str =”hello”;
代码区:存储逻辑代码的二进制
6-4 C++ 构造函数初始化列表…(05:28)
从栈中和堆中实例化的对象共同的特点,调用的构造函数都不用传递参数
在实例化对象时不需要传递参数的构造函数称为默认构造函数
初始化列表
- 初始化列表优先于构造函数执行.
- 初始化列表只能用于构造函数
初始化列表可以同时初始化多个数据成员
优点:给const常量赋值因此用初始化列表初始化比构造函数更好.
初始化列表先于构造函数执行,格式是在构造函数后面加::加数据成员名字(赋值)注赋值只能用(),不能用等号。默认构造函数(实例化时不需要传递参数)
1.Student(){};
2.Student(String name=”Jim”){}
初始化列表
Student():m_strName(“Jim”),m_iAge(10){}//多个以“,”隔开,用括号赋值
【特点】(效率高速度快,推荐使用)
1.初始化列表先于构造函数执行
2.初始化列表只能用于构造函数
3.初始化列表可以同时初始化多个数据成员
【如图中示例,若使用构造函数,在{}内对const进行赋值,系统会认为是对常量的二次赋值,将无法通过编译,因此此处只能使用初始化列表的方式(此处可以体现出代码的执行顺序!)】
因为构造函数在声明的时候加了默认值,所以在定义的时候就不用再加默认值了。
eg:
声明:Teacher(string name=”james”,int age=1);
定义: Teacher(string name,int age)
{
m_strName=name;
m_iAge=age;
}
6-7 C++ 拷贝构造函数(05:04)
如果没有自定义的拷贝构造函数则系统自动生成一个默认的拷贝构造函数,当采用直接初始化或者复制初始化实例对象时系统自动调用拷贝构造函数.
拷贝构造函数被调用的情形:
参数传递时、 复制赋值时、 直接初始化时
拷贝构造函数定义:
构造函数名(const 类名 &变量名)
(&是引用符号,&变量名可以不写。)
test(t1)是函数调用,调用test函数,传入实参t1,t1是类teacher的一个对象;
test函数参数不是引用或者指针类型,所以传参的时候是会拷贝t1,传入test函数的
使用条件:
通过同类型的对象实例化另外的对象时,自动调用拷贝构造函数。
注意:
拷贝构造函数的参数是确定的,不能重载。
例如:
Teacher(const Teacher &tea){}
拷贝构造函数一个作用是,内部成员如果是指针,指针指向一个缓冲区,那么当你拷贝时,只是拷贝了缓冲区指针,那么两个对象的内部成员指向的是同一个缓冲区,这个可能不是你想要的,所以自己编写拷贝构造函数可以重新申请一个缓冲区,并更新指针,这样两个对象就可以完全独立使用了
6-10 C++ 析构函数(05:08)
对象的生命历程
申请内存–初始化列表–构造函数==参与运算–析构函数–释放内存
析构函数–收拾残局,归还系统资源
析构函数: 就是为了返还资源的
~类名();
析构函数不能有参数,因此不能重载,没有回传值
在栈中实例化时在程序main函数执行完之后才会调用析构函数
在堆中实例化时只有在delete时才会调用析构函数
调用拷贝构造函数的对象也是同堆实例化的对象一样在窗口关闭之时自动调用析构函数
第7章 课程总结
7-2 综合练习
注意
- class后需要用分号;结束
- class默认是private成员
- 默认构造函数必须public,否则无法初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using namespace std;
/**
* 定义类:Student
* 数据成员:m_strName
* 无参构造函数:Student()
* 有参构造函数:Student(string _name)
* 拷贝构造函数:Student(const Student& stu)
* 析构函数:~Student()
* 数据成员函数:setName(string _name)、getName()
*/
class Student
{
public:
string m_strName;
Student(){};
Student(string _name){};
Student(const Student& stu){};
~Student(){};
void setName(string _name){
m_strName = _name;
}
string getName(){
return m_strName;
}
};
int main(void)
{
// 通过new方式实例化对象*stu
Student *stu = new Student();
// 更改对象的数据成员为“慕课网”
stu->setName("慕课网");
// 打印对象的数据成员
cout << stu->m_strName << endl;
return 0;
}