C++核心编程
-
- 1.命名空间——避免名称冲突,更好地控制标识符的作用域
- 2.内联函数——在适当的地方像预定义宏一样展开,不需要函数调用的开销(空间换时间)
- 3.内存分区模型——数据存放的区域不同,生命周期不同,使编程更加灵活
- 4.引用——给变量起别名
- 5.函数提高
- 6.类和对象——C++面向对象的三大特征:封装、继承、多态
- 7. 文件操作——文件可以将数据持久化
- 类型转换——C++的强制转换允许控制各种不同种类的强制转换,能更清晰的表明它们要干什么
- 异常——让一个函数在发现了自己无法处理的错误时抛出(throw)一个异常
1.命名空间——避免名称冲突,更好地控制标识符的作用域
1.1 命名空间的创建及调用
//创建命名空间A
namespace A {
int a = 10;
//嵌套命名空间B
namespace B {
int a = 20;
}
}
//命名空间只能全局范围内定义
//cout << "A::a : " << A::a << endl;
//可以随时把新的成员加入已有的命名空间中
namespace A {
void func() {
cout << "hello namespace!" << endl;
}
}
void test() {
cout << "A::a : " << A::a << endl;
cout << "A::B::a : " << A::B::a << endl;
A::func();
//起别名
namespace C = A::B;
cout << "C::a : " << C::a << endl;
}
1.2 using声明
namespace A{
int paramA = 20;
int paramB = 30;
void funcA(){
cout << "hello funcA" << endl; }
void funcB(){
cout << "hello funcA" << endl; }
}
void test(){
//1. 通过命名空间域运算符
cout << A::paramA << endl;
A::funcA();
//2. using声明
using A::paramA;
using A::funcA;
cout << paramA << endl;
//cout << paramB << endl; //未声明,不可直接访问
funcA();
//3. 同名冲突
//int paramA = 20; //相同作用域注意同名冲突
}
1.3 using编译指令
namespace A{
int paramA = 20;
int paramB = 30;
void funcA(){
cout << "hello funcA" << endl; }
void funcB(){
cout << "hello funcB" << endl; }
}
void test01(){
using namespace A;
cout << paramA << endl;
cout << paramB << endl;
funcA();
funcB();
//不会产生二义性
//命名空间中的 paramA 是全局变量,这里的 paramA 是局部变量
int paramA = 30;
cout << paramA << endl;
}
namespace B{
int paramA = 20;
int paramB = 30;
void funcA(){
cout << "hello funcA" << endl; }
void funcB(){
cout << "hello funcB" << endl; }
}
void test02(){
using namespace A;
using namespace B;
//二义性产生,不知道调用A还是B的paramA
//cout << paramA << endl;
}
2.内联函数——在适当的地方像预定义宏一样展开,不需要函数调用的开销(空间换时间)
//函数体和声明结合在一起
inline int func(int a) {
return a+1; }
class Person {
public:
Person() {
cout << "构造函数!" << endl; }
//任何在类内部定义的函数自动成为内联函数
void PrintPerson() {
cout << "输出Person!" << endl; }
};
void test() {
Person p;
p.PrintPerson();
}
3.内存分区模型——数据存放的区域不同,生命周期不同,使编程更加灵活
3.1 程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
存放CPU执行的机器指令
代码区是共享的,目的是对于频繁被执行的程序,只需要在内存中有—份代码即可
代码区是只读的,原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此
全局区还包含了常量区,字符串常量和其他常量也存放在此
该区域的数据在程序结束后由操作系统释放
3.2 程序运行后
栈区:
由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量,栈区开辟的数据由编译器自动释放
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟内存
int * func() {
//利用new关键字 可以将数据开辟到堆区
int* p = new int(10);
return p;
}
void test02() {
//创建10整型数据的数组,在堆区
int * arr = new int[10];
for (int i = 0; i < 10; i++) {
arr[i] = i + 100;
}
//首地址
cout << arr << endl;
for (int i = 0; i < 10; i++) {
cout << arr[i] << " " << &arr[i] << endl;
}
//释放内存
delete[] arr;
}
int main() {
int* p = func();
cout << *p << endl;
//释放内存用delete
delete p;
test02();
}
4.引用——给变量起别名
4.1 引用的使用
int main() {
int a = 10;
//使用引用
int& b = a;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
b = 100;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
return 0;
}
4.2 引用做函数参数
-
函数传参时,可以利用引用的技术让形参修饰实参
//引用传递_效果同地址传递 void swapaa(int& a, int& b) { int temp = a; a = b; b = temp; } int main() { int a = 10; int b = 20; swapaa(a, b); cout << a << endl; cout << b << endl; return 0; }
4.3 引用做函数返回值
//引用做函数的返回值
//1.不要返回局部变量引用
int& test01() {
int a = 10;//a为局部变量(栈区)
return a;
}
//2.函数的调用可以作为左值
int& test02() {
static int a = 20;//a为静态变量(全局区)
return a;
}
int main() {
int& ref = test01();
cout << "ref " << ref << endl;
cout << "ref " << ref << endl;
int& ref2 = test02();
cout << "ref2 " << ref2 << endl;
cout << "ref2 " << ref2 << endl;
//如果函数的返回值时引用,这个函数调用可以做左值
test02() = 1000;//a = 1000;
cout << "ref2 " << ref2 << endl;
cout << "ref2 " << ref2 << endl;
return 0;
}
4.4 引用的本质
-
引用的本质在C++内部实现是一个指针常量int * const p = &a;、
//发现是引用,转换为int* const ref = &a; void func(int& ref) { ref = 100;//ref是引用,转换为* ref = 100 } int main() { int a = 10; //自动转换为 int*const ref = &a;指针常量是指针指向不可改,也说明为什么引用不可更改 int& ref = a; ref = 20;//内部发现ref是引用,自动帮我们转换为:*ref = 20; cout << "a:" << a << endl; cout << "ref : " << ref << endl; func(a); return 0; }
4.5 常量引用
-
常量引用主要用来修饰形参,防止误操作
//引用使用的场景,通常用来修饰形参 void showValue(const int& v) { //v += 10; cout << v << endl; } int main() { //int& ref = 10; //错误,引用本身需要一个合法的内存空间 //加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;(注意会附加const属性) const int& ref = 10; //ref = 100; //加入const后不可以修改变量 cout << ref << endl; //函数中利用常量引用防止误操作修改实参 int a = 10; showValue(a); return 0; }
5.函数提高
5.1 函数的默认参数
//返回值类型 函数名 (参数= 默认值){}
int func(int a,int b = 10){
return a+b;
}
//1.如果某个位置已经有了默认参数,那么从这个位置往后都必须有默认值
int func2(int a = 10,int b){
return a+b;
}
//2.如果函数声明中有默认参数,函数实现就不能有默认参数
//出现二义性导致错误
int func2(int a = 10,int b = 10);
int func2(int a = 10,int b = 10){
return a + b;
}
5.2 函数占位参数
//函数占位参数,占位参数也可以有默认参数
void func(int a, int = 10) {
cout << "this is func" << endl;
}
int main() {
func(20);//占位参数必须填补
return 0;
}
5.3 函数重载
//同一个作用域下,函数名相同,参数类型不同 或者 个数不同 或者 顺序不同
void func() {
cout << "func 的调用" << endl;
}
void func(int a) {
cout << "func(int a)的调用" << endl;
}
void func(double a) {
cout << "func(double a)的调用" << endl;
}
void func(int a, double b) {
cout << "func(int a, double b)的调用" << endl;
}
int main() {
int a = 10;
double b = 20.5;
func();
func(a);
func(b);
func(a, b);
return 0;
}
6.类和对象——C++面向对象的三大特征:封装、继承、多态
6.1 封装
- 将属性和行为作为一个整体,表现生活中的事物
class 类名{
访问权限:属性/行为};
//示例(圆):
//圆周率
const double PI = 3.14;
//创建一个对象的类
class Circle {
public: //访问权限 公共的权限
int m_r;//半径
//行为
//获取到圆的周长
double calculateZC() {
//获取圆的周长
return 2 * PI * m_r;
}
};
int main() {
//通过圆类,创建圆的对象
//c1就是一个我们创造的圆
Circle c1;
c1.m_r = 10;
cout << "圆的周长为: " << c1.calculateZC() << endl;
return 0;
}
- 将属性和行为加以权限控制
//三种权限
//公共权限 public 类内可以访问 类外可以访问
//保护权限 protected 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容
//私有权限 private 类内可以访问 类外不可以访问 儿子不可以访问父亲中的私有内容
class Person {
public: //公共权限
string m_name;//姓名
protected://保护权限
string m_car;//汽车
private://私有权限
int m_password;//密码
public:
void func() {
//类内访问
m_name = "张三";
m_car = "摩托";
m_password = 123456;
}
};
int main() {
//实例化对象
Person p1;
p1.m_name = "李四";
p1.m_car = "汽车";//错误,不可访问
p1.m_password = 654321;//错误,不可访问
return 0;
}
- struct和class的区别
唯一区别:
//struct 默认权限为公共
//class 默认权限为私有
- 将成员属性设置为私有
//优点1:将成员属性设置为私有,可以自己控制读写权限
//优点2:对于权限,我们可以检测数据的有效性
class Person {
private:
//可读可写
string m_name;
//只读
int m_age;
//只写
string m_lover;
public:
void setname(string name) {
m_name = name;
}
string getname() {
return m_name;
}
int getage() {
m_age = 0;
return m_age;
}
void setlover(string lover) {
m_lover = lover;
}
};
int main() {
//实例化对象
Person p1;
p1.setname("张三");
p1.setlover("李四");
cout << "姓名为:" << p1.getname() << endl;
cout << "年龄为:" << p1.getage() << endl;
return 0;
}
6.2 对象的起始化和清理
6.2.1 构造函数和析构函数
//构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动
//析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
-
构造函数
-
构造函数,没有返回值也不写void
-