0.背景
C++的出现主要是为了解决C语言在软件开发中的一些问题,使得程序设计更加高效、灵活和易于维护。以下是一些导致C++出现的背景和问题: 面向对象编程:C语言虽然功能强大,但是在处理大型项目时,结构不够清晰,代码重用性和可维护性有限。C++引入了面向对象的编程思想,使得程序结构更加清晰,代码重用更容易。 数据抽象:C语言中没有提供封装数据和行为的机制,导致数据容易被误用或者修改。C++引入了类和对象的概念,实现了数据抽象,使得数据更加安全。 继承和多态:C语言中没有提供继承和多态的机制,导致代码复用性降低。C++通过继承和多态机制,使得代码结构更加灵活,可扩展性更强。 模板:C语言中没有泛型编程的支持,导致很多算法和数据结构需要重复编写多个版本。C++引入了模板的概念,实现了泛型编程,提高了代码的复用性和效率。 总的来说,C++的出现是为了弥补C语言在软件开发中的不足,提高程序设计的效率和质量。
一、C++概述(了解)
C++起初也叫“c with clsss”,c++是对c的扩展,因此c++是C语言的超集。这意味着任何有效的c语言程序都是有效的c++程序。
c语言和c++语言的关系
c++语言是在C语言的基础上添加了 面向对象编程 和 泛型编程 的支持。继承了C语言高效、简洁、快速和可移植的传统
-
C语言代表的过程性语言
-
c++在C语言基础上添加的类的面向对象语言
-
c++魔板支持的泛型编程
二、面向对象的三大特征(了解)
封装、继承、多态
三、命名空间(重点)
3.1.为什么要有命名空间
为了解决 多人合作时取重命名的标识符的 问题
命名空间是一种用来避免命名冲突的机制,它可以将代码划分为不同的作用域,使得相同名称的变量、函数或类可以在不同的命名空间中存在而不会发生冲突。
3.2.什么是命名空间
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 命名空间(只能定义在全局中)
namespace A{ // A是空间的名字
int a;
void func()
{
}
}
int main()
{
return EXIT_SUCCESS;
}
在使用命名空间时,可以通过::
操作符来访问特定命名空间中的变量、函数或类
3.3.命名空间的注意
-
命名空间只能写在全局中
-
命名空间可以 嵌套 命名空间
-
命名空间是开放的,随时可以加入新成员,但是新成员只能在加入后使用
3.4. ::作用域运算符
1)使用::
操作符访问全局变量
int a = 10;
int main()
{
int a = 20;
cout << "a:" << a << endl; // 20
cout << "::a:" << ::a <<endl; // 10
}
2)::
操作符来访问特定命名空间中的变量、函数或类
A::$variable; A::function(); A::Myclass myobject;
四、using声明和编译指令(重点)
-
using声明 :可以使命名空间中的指定的 标识符 能直接使用(类似python的from math import pi)。但是在该作用域内,不能重新定义一个相同的标识符
namsespace A
{
int a = 10;
}
int main()
{
cout << A::a << endl; // 每次访问A中a时,都需要::
// using声明后
using A::a;
cout << a << endl; // 就可以直接使用了
}
-
using编译指令:让某个命名空间中的 所有标识符 可以直接使用(包括不需要的标识符)如果与局部名称冲突,则局部名称将覆盖名称空间中的名称,而编译器并不会发出警告。
namespace A
{
int a = 10;
int b = 20;
}
int main()
{
using namespace A;
cout << a << endl; // 10
cout << b << endl; // 20
int a = 100; // 不会冲突
cout << a << endl; // 100(局部变量覆盖全局变量)
}
五、struct类型加强(重点)
-
c中定义结构体变量需要加上 struct 关键字,c++不需要。声明的时候一样要加struct,只不过不需要借助typedef来减少struct的书写
struct Make()
{
int a;
char str[64];
}
void test01()
{
Make a; // 申请空间给结构体变量。没有加struct,不会报错
}
-
c中的结构体只能定义成员变量,不能定义成员函数,而c++都可以
struct Make() { int a; void func() { cout << "func" << endl; } }
六、更严格的类型转换与三目运算符(了解)
6.1.更严格的类型转换
c++不能进行隐式转换数据类型,比C语言更严格
char *p = malloc(64); // malloc返回的指针是(void*)隐式转换成char*。c可以运行,c++会报错
char *p = (char*)malloc(64); // 都可以运行
6.2.三目运算符
-
左值 和 右值概念 在c++中可以放在赋值操作符左边的是左值,右边的是右值 有些变量既可以当左值,也可以当右值 左值为Lvalue,L代表Location,表示内存可以寻址,可以赋值 右值为Rvalue,R代表Read,就是可以知道它的值
-
C语言的三目运算符 返回的是 三目运算符的结果的右值
int a = 10;
int b = 20;
a > b ? a : b --> 返回的是20,而不是变量b
-
C++的三目运算符返回的是左值,是空间
int a = 10;
int b = 20;
a > b ? a : b = 100; --> 返回的是变量b
cout << b << endl; // b:100
七、C/C++的const(重点)
7.1.C语言
1)C语言的const修饰的变量都有空间
2)C语言的const修饰的全局变量具有外部链接属性
// 另一个c文件
const int c = 300; // 定义一个全局变量c,有内存
// c文件
const int a = 10; // 常量区,一旦初始化,不能修改
void test()
{
// a = 200; 全局变量不能直接修改
int *p = (int*)&a;
// *p = 100; 全局变量不能间接(通过指针)修改
}
int main()
{
const b = 20;
// b = 200; 局部的const不能直接修改
int *p = (int*)&b;
*p = 100; // 局部的const可以间接修改,此时b是100,打印b也是100
extern const int c; // C语言可以通过全局声明外部链接c
printf("%d/n", c); // 300
}
7.2.c++
7.2.1.c++const
1)C语言和c++的编译器不一样
c++编译器,在编译阶段,会把 const修饰的变量 换成 它的值(如果想禁止这种操作,用禁止优化:volatile)
2)c++的const修饰的变量有时有空间,有时没有空间(发生常量折叠,且没有对变量进行取址操作)
3)c++的const修饰的全局变量具有内部链接属性
在初始定义全局变量的时候加上extern 就变为外部链接属性
const int aa = 10; // 没有内存
void test()
{
// 发生了常量折叠
cout << "aa=" << aa << endl; // 在编译阶段,编译器:cout << "aa" << 10 << endl;(直接打印常量与打印变量时间不一样)
// 这样做的好处是:节省内存和时间
}
int main()
{
const int bb = 20; // 栈区
int *p = (int*)&bb; // 进行取址操作,所以有空间
*p = 200;
cout << "bb=" << bb << endl; // 20
// bb的值被修改成200.打印出20是因为编译器把这串代码改写成:cout << "bb=" << 20 << endl;
cout << "*p=" << *p << endl; // 200,bb确实被修改了
}
7.2.2.c++编译器不能优化的情况
1)如果用变量给const修饰的局部变量赋值,那么编译器不会优化
2)不能优化自定义数据类型
3)编译器是在编译阶段来优化数据
4)加上禁止优化:volatile
7.3.尽量用const替代#define
const 和 #define区别
1.define没有数据类型,const修饰的变量有数据类型,可以进行数据类型检查 2.const修饰的变量有作用域;define不重视作用域,只能在全局,不能限定常量的使用范围