C++Day1
C++概述
- 两大编程思想
- 面向对象
- 泛型编程
- 面向对象三大特性
- 封装
- 继承
- 多态
- ANSI在1998制定出C++第一套标准
初识C++
#include <iostream>
//iostream:标准输入输出流 相当于stdio.h
//i:input输入
//o:output输出
//stream:流
using namespace std;
//使用 命名空间 标准 使用标准命名空间
//程序入口函数
int main()
{
cout<<"hello world"<<endl;
//count:标准输出流对象
//<<:用于在count后拼接输出的内容
//endl:操纵符end line 结束当前行,并将与设备关联的缓冲区中的内容刷新到设备中。缓冲刷新操作可以保证到目前为止程序所产生的所有输出都写入输出流中,而不是停留在内存中等待写入
system("pause");//阻塞
return EXIT_SUCCESS;//返回正常退出
}
标准输入输出对象
- 标准库定义了四个IO对象
- cin:标准输入
- >>:输入运算符
- cout:标准输出
- **<< **: 输出运算符
- cerr: 标准错误(输出警告和错误消息)
- clog:输出程序运行时的一般性信息
注释
- //:当行注释
- /*内容 */:多行注释(注释界符)
- 注释界定符不可嵌套
- 单行注释可嵌套
双冒号作用域运算符
#include <iostream>
using namespace std;
int a=100;//全局变量
int main()
{
int a=200;
cout<<"a="<<a<<endl;
cout<<"全局a="<<::a<<endl;
//::代表作用域,如果前面什么都不添加代表全局作用域
return EXIT_SUCCESS;
}
#include <iostream>
//using namespace std;
int a=100;//全局变量
int main()
{
int a=200;
std::cout<<"a="<<a<<std::endl;
std::cout<<"全局a="<<::a<<std::endl;
//::为作用域运算符,加了std,表示要使用std内的东西
return EXIT_SUCCESS;
}
namespace命名空间
-
命名空间用途:解决名称冲突
-
int main() { A::a(); B::a(); }
-
-
命名空间下可放变量、函数、结构体、类等
-
namespace A { int m_A; void func(); struct Person { }; class Animal { }; }
-
-
命名空间必须要声明在全局作用域下
-
命名空间可以嵌套命名空间
-
namespace B { int m_A=10; namespace C { int m_A=20; } } void test() { cout<<"B空间下的m_A="<<B::m_A<<endl; cout<<"C空间下的m_A="<<B::C::m_A<<endl; }
-
-
命名空间是开放的,可以随时给命名空间添加新的成员
-
namespace B { int m_A=10; } namespace B { int m_B=100; } //二者合并
-
-
命名空间可以是匿名
-
namespace { int m_C=100; int m_D=200; //当写的命名空间是匿名的,相当于写了static int m_C=100;static m_D=200; } void test() { cout<<"m_C="<<m_C<<endl; cout<<"m_C="<<::m_C<<endl; }
-
-
命名空间可以起别名
-
namespace A { int m_A=100; } void test() { namespace B=A; cout<<"A::m_A"<<endl; cout<<"B::m_A"<<endl; }
-
using声明以及using编译指令
- using声明形式:using namespace::name;
- 头文件不应包含using声明。头文件的内容会拷贝到所有引用它的文件中去,如果头文件里有某个using声明,那么使用了该头文件的文件就都会有该声明,对于一些程序可能会有名称冲突
namespace KingGlory
{
int sunwukongId=1;
}
void test01()
{
cout<<KingGlory::sunwukongId<<endl;
}
//或
void test02()
{
//using声明
//当using声明与就近原则同时出现会出错
using KingGlory::sunwukongId;
cout<<sunwukongId<<endl;
}
void test03()
{
//using编译指令
using namespace KingGlory;
cout<<sunwukongId<<endl;
}
void texe04()
{
int sunwukongId=2;
using namespace KingGlory;
cout<<sunwukongId<<endl;//输出2
//当就近原则与using编译指令同时出现时,优先使用就近原则
//当using编译指令有多个,需要加作用域加以区分
}
const限定符
-
const对象一旦创建后其值不再改变,const对象必须初始化
-
默认状态下,const对象仅在文件中有效,当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义独立的变量
-
在const前无论声明还是定义都添加关键字extern可以使得只在一个文件定义const,而在其他多个文件声明并使用它
-
//file_1.cc定义并初始化一个常量,该常量能够被其他文件访问 extern const int bufSize=fcn(); //file_2.h头文件 extern const int bufSize;//与file_1.cc中定义的bufSize是同一个 //如果想要在多个头文件之间共享const对象,必须在变量的定义之前添加extern关键字
-
-
const的引用
-
将引用绑定到const对象上,为对常量的引用,不能被用作修改它所绑定的对象
-
const int ci=1024; const int &r1=ci; //ri=42;错误,r1是对常量的引用 //int &r2=ci;错误,试图让一个非常量引用指向一个常量对象
-
-
引用类型必须与所引用对象类型一致的两个例外
-
在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能够转换成引用的类型即可
-
允许一个常量引用绑定非常量的对象、字面值、一般表达式
-
int i=42; const int &r1=i;//允许将const int&绑定到一个普通int对象上 const int &r2=42; const int &r3=ri*2;//r3是一个常量引用 int &r4=r1;//错误,r4是一个普通非常量引用 -
double dval=3.14; const int &ri=dval; //编译器将代码变为以下形式 //const int temp=dval;//由双精度浮点数生成一个临时的整型常量 //const int &ri=temp;让ri绑定这个临时量 //临时量为当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象
-
指针和const
const double pi=3.14;
//double *ptr=π错误,ptr未一个普通指针
const double *cptr=π
-
const指针
-
把*放在const前面用以说明指针是一个常量,不变的是指针本身的指而非指向的那个值
-
int errNumb=0; int *const curErr=&errNumb;//curErr将一直指向errNumb const double pi=3.14; const double *const pip=π//pip是一个指向常量对象的常量指针 //pip是一个指向常量的常量指针,不论pip所值=指的对象值还是pip自己存储的地址都不能改变,curErr指向的是一个一般的非常量整数,完全可以用curErr去修改errNumb的值
-
顶层const
- 顶层const表示指针本身是一个常量
- 底层const表示指针所指的对象是一个常量
constexpr和常量表达式
-
常量表达式是指值不会改变并且在编译过程就可得到计算结果的表达式
-
在一个复杂的系统中,难以分辨一个初始值是不是常量表达式。C++中允许将变量声明为constexpr类型以便编译器来验证变量的值是否为一个常量表达式
-
constexpr int mf=20; constexpr int sz=size();//只有当size是一个constexpr函数时才是一条正确的声明语句 -
指针与constexpr
-
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指对象无关
-
const int *p=nullptr;//p是一个指向整型常量的指针 constexpr int *p=nullptr;//p是一个指向整数的常量指针 -
constexpr指针即可以指向常量,也可以指向非常量
-
constexpr int *np=nullptr;//np是一个指向整数的常量指针,其值为空 int j=0; constexpr int i=42;//i的类型是整型常量 //i和j都必须定义在函数体外 constexpr const int *p=&i;//p是常量指针,指向整型常量i constexpr int *p1=&j;//p1是常量指针,指向整数j
-
C++对C语言的增强与扩展
-
全局变量检测增强,C++检测出重定义
-
//C #include <stdio.h> int a; int a=10; int main() { return 0; } //可编译成功 -
//C++ #include <iostream> using namespace std; int a; int a=10; int main() { return EXIT_SUCCESS; } //无法编译,有错误
-
-
函数检测增强
- C语言的返回值、形参类型、函数调用参数个数没有检测
-
类型转换检测增强
-
struct增强
- C++结构体可以有函数,创建结构体变量可以简化关键字struct
-
bool类型扩展(C无该类型)
-
bool代表真与假 true(1) false(0)
-
bool flag=true; cout<<flag<<endl;//输出1
-
-
三目运算符增强
-
const增强
-
全局const
-
//C const int m_A=100;//受常量区保护,运行修改失败 void test() { //m_A=200; int *p=&m_A; *p=200; } -
//C++ const int m_A=100;//受常量区保护,运行修改失败 void test() { //m_A=200; int *p=(int *)&m_A; *p=200; }
-
-
局部const
-
//C void test() { const int m_B=100;//分配到栈上,可以修改 //m_B=200; int *p=&m_B; *p=200; } -
//C++ void test() { const int m_B=100;//分配到栈上,不 可以修改 //m_B=200; int *p=(int *)&m_B; *p=200; //C++下const修饰的变量称为常量,可以初始化数组 int arr[m_B]; }
-
-
const连接属性
- C语言下const修饰全局变量默认是外部链接属性
- C++下默认是内部链接属性,只有在本文件中才可以找到,可以加extern提高作用域
-
const分配内存情况
-
//对const变量取地址,会分配临时内存 void test01() { const int a=10; int * p=(int *)&a; } //使用普通变量初始化const变量,可以改变const变量的值 void test02() { int a=10; const int b=a; int *p=(int *)&b; *p=1000; cout<<"b="<<b<<endl;//输出1000 } //对于自定义数据类型 struct Person { string m_Name; int m_Age; }; void test03() { comst Person p; //p.m_Age=10;直接修改会失败 Person* pp=(Person *)&p; (*pp).m_Name="Tom"; pp->m_Age=10; cout<<"姓名:"<<p.m_Name<<"年龄:"<<p,m_Age<<endl; }
-
-
引用基本语法
-
引用的目的:起别名
-
类型:&别名=原名
-
void test01() { int a=10; int &b=a; b=100; cout<<"a="<<a<<endl;//100 cout<<"b="<<b<<endl;//100 } void test02() { int a=10; //int &b;错误,引用必须初始化。一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起,无法将引用重新绑定到另一个对象。引用并非对象,只是为一个已经存在的对象起的另一个名字 int &b=a; //引用一旦初始化后不可以引向其他变量 int c=100; //b=c为赋值,不是引用 } //对数组建立引用 void test03() { //直接建立引用 int arr[10]; int(&pArr)[10]=arr; //先定义出数组类型,在通过类型定义引用 typedef int(ARRAY_TYPE)[10]; ARRAY_TYPE & pArr2=arr; }
引用注意事项
//引用必须引一块合法内存空间
//int &a=10;
//不要返回局部变量的引用
int& func()
{
int a=10;
return 10;
}
void test()
{
int &ref=func();
cout<<"ref="<<ref<<endl;//输出10,第一次会保留
cout<<"ref"<<ref<<endl;//输出乱码,第一次以后局部变量会释放,若在func()中int前加static则不会
}
//引用不是对象,没有实际地址,不能定义指向引用的指针
空指针
//生成空指针的方法
int *p1=nullptr;//等价于int *p1=0;常用
int *p2=0;//直接将p2初始化为字面常量0
int *p3=NULL;//需有#include cstdlib
//预处理变量NULL.当用到预处理变量时,预处理器会自动将其替换为实际值
void*指针
- void*是一种特殊的指针类型,可以用于存放任意对象的地址
- 利用void*可以做的事情比较有限
- 与别的指针进行比较
- 作为函数的输入输出
- 赋给另一个void*
- 不能直接操作void指针所指的对象,因为无法知道是什么类型。以void的视角看内存空间仅是内存空间,无法访问内存空间中所存的对象
指针的引用
int i=42;
int *p;//p为一个int指针
int *&r=p;//r是一个对指针p的引用
r=&i;//r引用了一个指针,将r赋值&i就是令p指向i
读取数量不定的输入数据
#include <iostream>
using namespace std;
int main()
{
int sum=0,value=0;
//读取数据直到遇到文件尾,计算所有读入的值的和
while(cin>>value)
{
sum+=value;
}
cout<<"sum is"<<sum<<endl;
return EXIT_SUCCESS;
}
//当使用一个istream对象作为条件时,效果是检测流的状态。如果流是有效的,即流未遇到错误,则检测成功。当遇到文件结束符或一个无效输入时,istream对象的状态会变为无效。处于无效状态的istream对象会使条件变为假
- 输入文件结束符
- windows:Ctrl+Z 然后按Enter或Return
- Unix与Mac OS X:Ctrl+D
局部静态对象static
- 在程序的执行路径第一次经过对象定义语句时初始化,直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会有影响
- 如果局部静态变量没有显式的初始值,其将执行值初始化,内置类型的局部静态变量初始化为0
补充
- 自动对象:只存在于块执行期间的对象
- 形参是一种自动对象。函数开始时为形参申请存储空间,因为形参定义在函数体作用域之内,一旦函数终止,形参就被销毁

1743

被折叠的 条评论
为什么被折叠?



