初识C++以及C++对C的增强和扩展
1 C++ 概述
1.1 C++两大编程思想
1. 面向对象
2. 泛型编程
1.2 C++移植性和标准
- ANSI在1998制定出C++第一套标准(C++98)
2 初识C++
2.1 面向对象的三大特性
封装、继承、多态
2.2 头文件以及标准命名空间
#include <iostream> // 标准输入输出流
using namespace std; // 标准命名空间
2.3 双冒作用域运算符
:: // 双冒作用域运算符
std::cout; // std作用域下的cout
::a; // ::前面什么都不添加 代表全局作用域
2.4 namespace命名空间
- 命名空间的用途?
解决名称冲突问题
- 命名空间下可以存放什么?
变量、函数、结构体、类…
-
命名空间必须要声明在全局作用域
-
命名空间可以嵌套命名空
namespace A
{
int a_;
namespace B
{
int a_;
}
}
int a = A::a_; // 命名空间A下的a_
int a = A::B::a_; // 命名空间A中命名空间B下的a_
- 命名空间是开放的,可以随时将新成员添加到命名空间下
namespace A
{
int a_;
}
namespace B
{
int b_;
}
namespace A
{
int c_;
}
// 相当于
namespace A
{
int a_;
int c_;
};
namespae B
{
int b_;
}
- 命名空间可以匿名的
namespace
{
int a_ = 100;
int b_ = 10;
// 相当于写了static int a_ = 100; static int b_ = 10;
}
// 相当于全局变量,直接使用
cout << "a_ = " << a_ << " b_ = " << b_ << endl;
- 命名空间可以起别名
namespace longName
{
int a_ = 100;
}
void test()
{
// 命名空间起别名
namespace lN = longName;
cout << "a_ = " << lN::a_ << endl;
}
2.5 using声明以及using编译指令
2.5.1 using声明
1.using 命名空间名::成员名;
2.当使用using声明去声明了一个命名空间中的变量,在函数中有一个相同的变量名,会报错,尽量避免
namesapce Person
{
int age_ = 18;
}
void test()
{
// using 声明
using Person::age_;
// 与using声明的命名空间Person中的age_变量名相同,会报错
int age_ = 20;
// 此处,因为函数中有age_变量,所以即使声明了命名空间Person, 下方打印仍然输出age_ = 20(就近原则)
cout << "age_ = " << age_ << endl;
}
2.5.1 using编译指令
1.using namespace 命名空间名;
2.当using编译指令 与 就近原则同时出现,优先使用就近原则
3.当using编译指令有多个,需要加作用域 区分
namespace Person
{
int age_ = 18;
}
namespace Dog
{
int age_ = 5;
}
// 第一种情况
void test1()
{
// using编译指令声明命名空间
using namespace Person;
// 与using编译指令声明的命名空间Person中的age_变量名相同
int age_ = 20;
//此处,因为函数中有age_变量,所以即使使用了using编译指令声明命名空间Person, 下方打印仍然输出age_ = 20(就近原则)
cout << "age_ = " << age_ << endl;
}
// 第二种情况
void test2()
{
// using编译指令声明命名空间
using namespace Person;
using namespace Dog;
//此处,因为Person命名空间和Dog命名空间都有age_变量, 所以下方打印需要加作用域
cout << "Person::age_ = " << Person::age_ << endl; // age_ = 18
cout << "Dog::age_ = " << Dog::age_ << endl; // age_ = 5
}
3 C++对C语言增强以及扩展
3.1 全局变量检测增强
int a;
int a = 10;
// 在C语言中,可以这样使用,相当于赋值 int a; a = 10;
// 在C++语言中,编译错误
3.2 函数检测增强
C语言:返回值没有检测 形参类型没有检测 函数调用参数个数没有检测
C++语言:返回值检测、形参类型检测、函数调用参数个数
// 在C语言中
// 1 函数的返回值没有检测
// 2 形参类型没有检测
// 3 函数调用参数个数没有检测
getRectS( w , h)
{
return w *h;
}
void test()
{
printf("%d\n", getRectS(10, 10, 10));
}
3.3 类型转换检测增强
C语言:char * p = malloc(64);
C++语言:char * p = (char *)malloc(64);
// malloc返回类型为void*,在C语言中可以这样使用
void test()
{
char * p = malloc(64);
}
// 在C++语言中必须强转
void test()
{
char * p = (char *)malloc(64);
}
3.4 struct 增强
C语言:结构体中不可以有函数,创建结构体变量不可以简化struct
C++语言:结构体中可以有函数,创建结构体变量可以简化struct
struct Person
{
int age_;
//void func(); C语言下 结构体中不可以有函数
};
// 1.C++可以在结构体中放函数
// 2.创建结构体变量,可以简化关键字struct
void test()
{
struct Person p1; // c
Person p2; // c++
}
3.5 bool数据类型扩展
C++才有bool类型
// C++才有bool类型
// 代表真 --- 1 true 假 ---- 0 false
bool flag; // true/false
3.6 三目运算符增强
C语言:返回的是值,只能做左值
C++语言:返回的是变量,可以做左值,也可以做右值
int a = 10;
int b = 20;
int c;
//C语言下返回的是值,只能做左值
c = a > b ? a : b; // c = 20
// a > b ? a : b = 100 相当于 20 = 100; 错误
*(a > b ? &a : &b) = 100; // b = 100
//C++语言下返回的是变量,可以做左值,也可以做右值
a > b ? a : b = 100; // 返回b, b = 100;
3.7 const增强
C语言:
- 全局 const 直接修改->失败 ,间接修改(通过指针) ->语法通过,运行失败
- 局部 const 直接修改 ->失败 ,间接修改(通过指针)-> 成功
- int arr[A]; 在C语言下 const是伪常量,不可以初始化数组
C++语言:
- 全局 const 和C结论一样
- 局部 const 直接修改->失败 ,间接修改(通过指针)-> 失败
- int arr[B]; C++中const可以称为常量,可以初始化数组
// C语言下
// 全局const 直接修改 失败 间接修改(通过指针) 语法通过,运行失败
// 局部 const 直接修改 失败 间接修改(通过指针) 成功
// int arr[A]; 在C语言下 const是伪常量,不可以初始化数组
const int A = 20; // 全局
void test1()
{
// 1.全局
/*
// 直接修改失败
A = 100;
// 间接修改失败
int *p = &A;
*P = 40;
*/
// 2.局部
const int B = 10; // 局部
// B = 30; // 直接修改失败
// 间接修改成功
int *p = &B;
*p = 100; // B = 100
}
// C++语言下
// 全局 const 和C结论一样
// 局部 const 直接修改失败 间接修改(通过指针) 失败
// C++中const可以称为常量,可以初始化数组
const int C = 20; // 全局
void test2()
{
// 1.全局
/*
// 直接修改失败
C = 100;
// 间接修改失败
int *p = &C;
*P = 40;
*/
// 2.局部
/*
const int D = 10; // 局部
// 直接修改失败
D = 30;
// 间接修改失败
int *p = &D;
*p = 100;
// 相当与int temp = D; int *p = &temp; *p = 100;(temp = 100)
// 修改的是一个临时变量的值,实际上D的值没有被修改
*/
}
4 const 链接属性
C语言下 const修饰的全局变量默认是外部链接属性
C++下 const修饰的全局变量默认是内部链接属性,可以加extern 提高作用域
// test.cpp 文件
// C语言中
const int g_a = 100;
// C++语言中
extern const int g_b = 100;//默认是内部链接属性 可以加关键字 extern 提高作用域
// 使用全局变量g_a,C和C++一样
void test()
{
extern const int g_a;
printf("%d\n", g_a);
}
5 const 分配内存情况
- 对const变量取地址 ,会分配临时内存
- 使用普通变量来初始化const变量,栈内存(可通过间接方式修改const变量)
- 对于自定义数据类型,栈内存(可通过间接方式修改const变量)
//1、对const变量取地址,会分配临时内存
void test01()
{
const int a = 10;
int * p = (int *)&a;
// 相当于 int tmp = a; int *p = &tmp;
}
//2、使用普通变量来初始化const变量
void test02()
{
int a = 10; // 栈内存
const int b = a; // 栈内存
int *p = (int *)&b;
*p = 1000; // a =100, b = 1000
}
//3、对于自定义数据类型
struct Person
{
string m_Name;
int m_Age;
};
void test03()
{
const Person p; // 栈内存
Person * pp = (Person *)&p;
(*pp).m_Name = "Tom"; // p.m_Name为Tom
pp->m_Age = 10; // p.m_Age = 10
}
6 面向对象和面向过程
面向对象: 狗.吃(狗粮)
面向过程: 吃(狗,狗粮)
7 扩展阅读
尽量用const代替define
define出的宏常量,没有数据类型、不重视作用域(不进行编译,在预处理阶段展开)
#difine FLAG 10
// 用const代替define
const int FLAG = 10;