C++核心编程

内存分区模型

c++程序在执行时,将内存大方向划分为4个区域

  • 代码区:存放函数体的二进制代码,由操作系统进行管理
  • 全局区:存放全局变量和静态变量以及常量
  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

意义:

不同区域存放的数据,赋予不同的生命周期,给我们强大的灵活编程

程序运行前

在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域

代码区:

存放cpu执行的机器指令

代码区是共享且只读的

全局区:

全局变量和静态变量存放至此

全局区还包含了常量区,字符串常量和其他常量也存放至此

该区域的数据在程序结束后由操作系统释放

类和对象

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

C++认为万事万物皆为对象,对象有其属性和行为

封装

语法:class类名{访问权限:属性 / 行为}

示例一:设计一个园类求圆的周长

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
const double PI = 3.14;
class circle
{
//访问权限
public://公共权限
//属性
int m_r;//半径
//行为
double calculateZC()//获取圆的周长
{
return 2*PI*m_r;
}
};
int main()
{
//实例化(通过一个类 创建一个对象的过程)
circle c1;//通过园类 创建具体的圆
c1.m_r=10;//给圆对象的属性进行赋值
cout<<"圆的周长为:"<<c1.calculateZC()<<endl;
return 0;
}

示例二:设计一个学生类

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
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
//属性
string m_Name;//姓名
int m_ID;//学号
//行为
void showstudent//显示姓名和学号
{
cout<<"姓名:"<<m_name<<"学号:"<<m_ID<<endl
}
//给姓名赋值
viod setname(string name)
{
m_name=name;
}
};
int main()
{
//实例化对象
student s1;//s1赋值
s1,m_name="张三";
s1.m_ID = 1;
s1.showstudent();//显示学生信息
student s2;
s2.m_name ="李四";
s2.m_ID=2;
s2.showstudent();
s3.setname("王五");//另外一种赋值方式
s.m_ID=;
s3.showstudent();
return 0;
}

访问权限:

1.public 公共权限 类内可以访问 类外可以访问

2.protected 保护权限 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容

3.privet 私有权限 类内可以访问 类外不可以访问 儿子不可以访问父亲的私有内容

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
#include <iostream>
#include <string>
using namespace std;
class person
{
public://公共权限
string m_name;//姓名
protected://保护权限
string car;
private://私有权限
int m_password;//银行卡密码
private:
void func()
{
m_name = "张三";
m_car = "拖拉机";
m_password = 123456;
}

};
int main()
{
person p1;//实例化具体对象
p1.m_name = "李四";
//p1.m_car = "奔驰";//报错 保护权限内容类外访问不到
//p1.m_password = 123;//报错 私有权限内容类外不可以访问
return 0;
}

struct和class的区别

c++中二者默认的访问权限不同

  • struct 的默认权限是 public
  • class 的默认权限是 private

成员属性设置为私有

优点:

1.将所有成员属性设置为私有,可以控制读写权限

2.对于写权限,我们可以检验数据的有效性

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>
using namespace std;
class person
{
public:
//写(设置)姓名
void setname(string name)
{
m_name = name;
}
//读(获取)姓名
string getname()
{
return m_name;
}
//读(获取)年龄
string getage()
{
m_age = 0;//初始化年龄
return m_age;
}
//年龄 想要可读可写 想要修改设置范围(0~150)
string getage()
{

return m_age;
}
//设置年龄
void set_age(int age)
{
if(age<0||age>150)
{
cout <<"输入有误" <<endl;
return;
}
m_age = age;
}
//设置情人
viod setlover(string lover)
{
m_lover = lover;
}
private:
string m_name;//姓名 可读可写
int m_age;//年龄 只读
string lover;//情人 只写
};
int main()
{
person p;
p.m_name = "张三";//报错
p.setname("张三");
cout<<"姓名为:"<< p.getname() << endl;
p.m_age =18;//报错
p.setage(18);//报错 无函数
cout<<"年龄为:"<< p.getage() << endl;
p.setlover("李四");
cout<<"情人为:"<< p.m_lover << endl;//报错
cout<<"情人为:"<< p.getlover() << endl;//报错 无函数
p.set_age(1000);//进行有效性验证//返回错误
p.set_age(18);//正常
return 0;
}

对象的初始化和清理

每个对象的初始设置以及对象销毁前的清理数据的设置

构造函数和析构函数

对象的初始化和清理也是两个非常重要的安全问题

c++利用以上两者解决上述问题,并且会被编译器自动调用,完成上述的工作

但是编译器提供的构造函数和析构函数是空实现

  • 构造函数:创造对象时为其成员属性赋值
  • 析构函数:令对象进行销毁,执行一些清理工作

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

1.构造函数,没有返回值也不写void

2.函数名称与类名相同

3.构造函数可以有参数,因此可以发生重载

4.程序在调用对象的时候会自动调用构造,无需手动调用,并且只会调用一次

析构函数语法:~类名(){}

1.析构函数,没有返回值也不写void

2.函数名称与类名相同,在名称前加上~

3.析构函数不可以有参数,因此不可以发生重载

4.程序在对象销毁前会自动调用析构,无需手动调用,并且只会调用一次

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
#include <iostream>
#include <string>
using namespace std;
//对象的初始化和清理
//1.构造函数进行初始化
class person
{
public:
//1.1构造函数
//没有返回值 不用写void
//函数名 与类名相同
//有参数 可以进行重载
//创建对象的时候会自动调用,且调用一次
person()
{
cout <<"person 构造函数的调用"<<endl;
}
//2.析构函数进行清理
~person()
{
cout<<"Person的析构函数调用"<<endl;
}
}
viod tset01()
{
person p;//在栈上的数据,test01执行完毕后,释放这个对象
}
int main()
{
test01();
person p;//只够构造没有析构 因为有下行代码
system("pause");
return 0;
}

构造函数的分类及调用

两种分类方式:

​ 按参数分为:有参构造和无参构造

​ 按类型分为:普通构造和拷贝构造

三中调用方式:

​ 括号法

​ 显示法

​ 隐式转换法

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
using namespace std;
class person
{
public:
//构造函数
person()//无参构造(默认构造)
{
age = a;
cout<<"person的无参构造函数调用"<<endl;
}
person(int a)//有参构造
{
age = a;
cout<<"person的有参构造函数调用"<<endl;
}
person(const person &p)//拷贝构造函数
{
age = p.age;
cout<<"person的拷贝构造函数调用"<<endl;
}
~person()
{
cout<<"person的析构函数调用"<<endl;
}
int age;

}
//调用
void test01()
{
//1.括号法
person p;//默认构造函数调用
person p2(10);//调用有参构造函数
person p3(p2);//拷贝构造函数
cout<<"p2的年龄为:"<<p2.age<<endl;
cout<<"p3的年龄为:"<<p3.age<<endl;
//注意事项
//调用默认构造函数时,不要加()
//因为编译器会认为这是一个函数声明,不会认为是在创造对象
//2.显示法
person p1;
person p2 =person(10);//有参构造
person p3 =person(p2);//拷贝构造
person(10);//匿名对象 特点:当前行执行结束后,系统会立即回收匿名对象(马上进行析构)
//注意事项
//不要用拷贝构造函数 初始化匿名对象 编译器会认为person p3 == person (p3),会认为是对象声明
//3.隐式转换法
person p4 = 10;//相当于写了 person p4 = person(10);//有参构造
person p5 =p4;//拷贝构造函数
}
int main()
{
system("pause");
return 0;
}