c向c++的过渡
一、面向对象
1.C++是C的继承;
2.C++即擅长面向对象的程序设计,又能做面向过程的程序设计;
实现某类事物的方法(函数)和属性(变量)封装成一个整体,一般封装成类,
当用户想去完成这类事物时,只需要知道这个类怎么用就行,因为类中已经
将所需的完事万物都包含进来了,一切皆对象。
二.c++的一些基本特点
1.C++是兼容C的,兼容大部分的C(C++的编译器更严格)
void func(void *p){
int *q = p;//C++不允许隐式的将void *转成 int *
//C++的编译器更严格
printf("*q = %d\n",*q);
}
int main(int argc, const char *argv[])
{
int a = 5;
func(&a);
return 0;
}
2.C++源文件的后缀名
*.cpp** .C .cxx .cc
3.C++的头文件是没有.h的
如: #include
C++兼容C的头文件
#include
\#include //C++包含C头文件常用的方式
4.编译器:
使用g++来编译c++文件
g++ xxx.cpp -o a.out
也可以使用gcc 编译,需要连接C++的库
gcc xxx.cpp -o a.out -lstdc++ //有的编译器不支持这种用法
三.第一个程序
1.hello world 程序说明
#include <iostream>
//iostream 输入输出流的头文件
using namespace std;
//using namespace //使用命名空间 ----用来解决命名污染问题的
//std 是标准命名空间 cout cin 等都是定义在std命名空间里的
//C++的编译器更严格,要求main函数返回值必须是 int
int main(){
//cout 输出流对象 功能就是将要输出的信息 输出到终端
//:: 作用域限定符 用来表示范围的
//std::cout 表示使用std命名空间中的 cout
//endl 换行
std::cout<<"hello world"<<std::endl;
//<< 输出流运算符 可以级联使用,将信息按顺序输出到终端
std::cout<<"aa"<<" "<<"bb"<<" "<<"hqyj"<<std::endl;
return 0;
}
2.输出流对象cout
#include <iostream>
using namespace std;
int main(){
int a = 10;
char b = 'M';
std::cout<<"整型a:"<<a<<" "<<"字符型b:"<<b<<std::endl;
return 0;
}
3.输入流对象cin
#include <iostream>
using namespace std;
int main(){
int age;
char name;
//cin不加endl
std::cin >> age >>name;
std::cout<<"-------------------"<<std::endl;
std::cout<< name <<"出生于"<< 2022-age <<"年"<<std::endl;
}
4.cout 格式化输出
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a = 64;
cout<<"dec:"<<dec<<a<<endl; //以十进制形式输出整数
cout<<"hex:"<<hex<<a<<endl; //以十六进制形式输出整数a
cout<<"oct:"<<setbase(8)<<a<<endl; //以八进制形式输出整数a
//C++要求指针指向字符串常量 必须加 const
const char *pt="China"; //pt指向字符串"China"
cout<<pt<<endl;
cout<<setw(10)<<pt<<endl; //指定域宽为,输出字符串
cout<<setfill('*')<<setw(10)<<pt<<endl; //指定域宽,输出字符串,空白处以'*'填充
double pi = 3.1415926;
cout<<"pi="<<pi<<endl;//默认6位有效数字
cout<<"pi="<<setprecision(8)<<pi<<endl;//8位有效数字
cout<<"pi="<<setprecision(2)<<2.387654<<endl;//两位有效数字
return 0;
}
四.命名空间(名字空间)
1.c++中名字:
函数名、变量名、结构体名、枚举名、类名等。。。
2.命名空间的作用
防止命名污染,相当于给"名字"起了一个"姓氏"
命名污染:大型项目开发过程中,不同的开发人员定义相同的名字。
3.std 标准命名空间
使用标准命名空间中的内容都需要加 std
4.使用命名空间的方式:
1.每次使用时,都加 命名空间名::
std::cout<<“hello”<<std::endl;
std::cout<<“world”< <std::endl;
#include <iostream>
int main(){
std::cout<<"hello"<<std::endl;
return 0;
}
2.可以提前声明使用哪里的名字
using std::cout;
using std::endl;
//上面两句代码表示:后面要用到的所有的cout 和endl 都是std里面的
//但是每行只声明了一个
#include <iostream>
using std::cout;
using std::endl;
int main(){
cout<<"hello"<<endl;
return 0;
}
3.可以提前声明使用整个命名空间中的名字
using namespace std;
//上面代码表示:使用std命名空间中的所有名字,
后面再使用 cout cin endl 等时就都不用加 std::
#include <iostream>
using namespace std;
int main(){
cout<<"hello"<<endl;
return 0;
}
4.自己编写命名空间
namespace 命名空间名{
类型1 变量名1;
类型2 变量名2;
...
类型n 变量名n;
}
#include <iostream>
#include <cstring>
using namespace std;
namespace Teacher{
int age;
char name[32];
}
//using Teacher::age;//访问自己写的命名空间的方式2
//using Teacher::name;//访问自己写的命名空间的方式2
using namespace Teacher;//访问自己写的命名空间的方式3
int main(){
//Teacher::age = 20;//访问自己写的命名空间的方式1
age = 18;
strcpy(name,"yangfs");
cout<<name<<" "<<age<<endl;
return 0;
}
5.当多个命名空间中出现重复名字的时候
冲突情况1
#include <iostream>
using namespace std;
namespace Teacher{
int age;
char name[32];
}
namespace Student{
int age;
char name[32];
}
using namespace Teacher;
using namespace Student;
int main(){
//age = 18;//有歧义 会报错
Teacher::age = 18;//可以使用 命名空间名:: 来指定使用的是哪个age
return 0;
}
冲突情况2
#include <iostream>
using namespace std;
namespace Teacher{
int age;
char name[32];
}
int age;//没有被任何命名空间包住的名字 默认都放在匿名空间中
char name[32];
using namespace Teacher;
int main(){
::age = 18;//访问匿名空间中名字的方式
//不加命名空间名 但是 :: 必须加
cout<<::age<<" "<<Teacher::age<<endl;
return 0;
}
冲突情况3
#include <iostream>
using namespace std;
namespace Teacher{
int age;
char name[32];
}
using namespace Teacher;
int main(){
int age;
age = 18;//当局部变量名和命名空间中的变量名冲突时
//采用局部优先原则,默认使用的是局部变量
//如果想使用命名空间中的 age
//需要按下面的用法
Teacher::age = 20;
cout<<age<<" "<<Teacher::age<<endl;
return 0;
}
6.命名空间中封装函数名
#include <iostream>
#include <cstring>
using namespace std;
namespace Teacher{
int age;
char name[32];
void func();//命名空间中只保留函数的声明
}
//命名空间外定义函数的写法
void Teacher::func(){
cout<<age<<" "<<name<<endl;
}
using namespace Teacher;
int main(){
Teacher::age = 20;
strcpy(name, "yangfs");
func();
return 0;
}
7.命名空间使用总结
1.命名空间使用方式1: std::cout;
2.命名空间使用方式2: using std::cout;
3.命名空间使用方式3: using namespace std;
4.当名字有冲突时,需要是用 命令空间名:: 来区分;
5.没有被任何命名空间包住的名字,默认都在匿名空间空,访问方式 ::名字
6.当命名空间中的名字和局部变量冲突时,采用局部优先原则;
五.C++中支持两种风格的字符串
1.C++中支持两种风格的字符串
1.C风格:首地址、尾0 的风格
char str1[32] = “hello”;
const char * p = “hello”;
2.C++风格:C++中新增了 string 类型
使用string类型要求:
必须加头文件 #include
必须加头文件 #include //注意:千万不要写成 string.h
必须加 using namespace std;
//有些编译器 加了std 后,不加string 也不报错,但是最好加上
2.string类型的赋值和初始化
1.只有一个变量时:
string s1; s1 = “hello”;
string s2 = “world”;
string s3(“beijin”);
string s7(5, ‘a’);//用 “aaaaa” 初始化s7 --不常用
2.有两个变量时:
string s4; s4 = s3;
string s5 = s2;
string s6 = s1 + s2;
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
string s1 = "hello";
string s2;
s2 = "world";
string s3("hqyj");
string s4(5, 'a');
string s5;
s5 = s1;//strcpy
string s6 = s2;
string s7 = s1 + " " + s2;
cout<<"s1 = "<<s1<<endl;
cout<<"s2 = "<<s2<<endl;
cout<<"s3 = "<<s3<<endl;
cout<<"s4 = "<<s4<<endl;
cout<<"s5 = "<<s5<<endl;
cout<<"s6 = "<<s6<<endl;
cout<<"s7 = "<<s7<<endl;
return 0;
}
3.C风格和C++风格字符串的转换
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
int main(int argc, char const *argv[])
{
string s = "hello world";
//C++中不建议使用C风格的字符串。
//但是有些函数的参数又要求使用C风格字符串:printf sprintf fprintf
printf("s = %s\n", s.c_str());
}
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
string s = "hello";
if("hello" == s){
cout<<"yes"<<endl;
}else{
cout<<"no"<<endl;
}
}
4.string类的两个重要函数
1.size()
功能:返回字符串的长度(不包括 ‘\0’)—strlen
2.empty()
功能:返回字符串是否为空,空返回真 非空返回假
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
string s1 = "";
string s2 = "hqyj";
cout<< s1.size() <<endl;//0
cout<< s2.size() <<endl;//4
if(s1.empty()){
cout<<"NULL"<<endl;
}else{
cout<<"NOT NULL"<<endl;
}
}
5.string类型的比较
可以直接使用关系运算符比较
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
string s1 = "helloasgdf";
string s2 = "hwllo";
//strcmp
if(s1 == s2){
cout<<"yes"<<endl;
}else{
cout<<"no"<<endl;
if(s1 > s2){
cout<<"s1 > s2"<<endl;
}else if(s1 < s2){
cout<<"s1 < s2"<<endl;
}
}
}
6.string类型的输入
cin 可以输入string类型,但是不能输入带有空格的字符串
int main(int argc, char const *argv[])
{
string s;
cin>>s;//hello world
cout<<s<<endl;//hello
}
如果想输入带有空格的字符串,可以使用 getline 函数
int main(int argc, char const *argv[])
{
string s;
getline(cin, s);//hello world hqyj
cout<<s<<endl;//hello world hqyj
}
7.string类型对成员的访问
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
string s = "hello";
s.at(1) = 'M';//对string类型单个成员的访问
s[2] = 'L';//对string类型单个成员的访问
for(int i = 0; i < s.size(); i++){
//cout<<s[i];
cout<<s.at(i);
}
cout<<endl;
}
六.bool类型
C++中新增bool类型,用来表示真假的
bool类型只有两个值:true(1) false(0)
0为假,非0即为真。
使用bool类型可以防止 魔鬼数字。
true 和 false 是常量,可以用来给bool类型的变量赋值
#include <iostream>
using namespace std;
int main(){
bool b1 = 10;
bool b2 = 0;
bool b3 = -10;
cout<<b1<<endl;//1
cout<<b2<<endl;//0
cout<<b3<<endl;//1
bool b4 = true;
bool b5 = false;
cout<<b4<<endl;//1
cout<<b5<<endl;//0
//注意 true 和 false 是常量
//可以给bool类型的变量赋值
//但是不能被赋值
//true = 10;
cout<<"-----------------"<<endl;
//可以将bool类型按 true false 输出
//设置之后后面所有的bool类型都按 true false输出
cout<<boolalpha<<b1<<endl;//ture
cout<<b2<<endl;//false
//取消true false 改为 1 0 输出
cout<< noboolalpha << b4 <<endl;//1
cout<<b5<<endl;//0
return 0;
}
bool类型的大小:bool类型大小为1个字节,
本质上bool类型有一个bit就够了,但是因为操作系统分配内存的最小单位是字节
所以bool类型的大小才是一个字节。
七.引用(reference)
1.概念
引用是C++对C的一个重要扩充。
作用是给变量起个别名。 (类似于linux中的硬链接文件)
2.定义引用
& 定义引用是,作用是引用标识符,标识定义的是一个引用;
在C++中 & 有三个作用:
1.定义引用时,表示引用标识符,标识定义的是一个引用;
2.有两个操作数时,a&b,位运算的 按位与
3.其他场景都表示 取变量地址的意思
格式:
类型名 &引用名 = 引用的目标;
如
int a = 10;
//定义一个引用r 引用的目标是a
//定义成功后,使用r 和使用 a就是一样的了
int &r = a;
要求:
1.定义引用时必须要有引用的目标来初始化;
2.引用和引用的目标类型要保持一致;//继承和多态除外;
3.引用的目标一旦确定了,后面就不能再修改引用的目标了;
3.引用的基本使用
#include <iostream>
using namespace std;
int main(){
int a = 520;
int b = 100;
//定义一个引用r 引用目标是a
int &r = a;
//int &r2;//引用必须初始化
cout<<"a = "<<a<<" r = "<<r<<endl;//520 520
cout<<"&a = "<<&a<<" &r = "<<&r<<endl;//一样的
r = 1314;
cout<<"a = "<<a<<" r = "<<r<<endl;//1314 1314
a = 0;
cout<<"a = "<<a<<" r = "<<r<<endl;//0 0
r = b;//这种用法不是改变 r 引用的目标
//而是将 b 的值赋给 r 一份
cout<<"&a = "<<&a<<" &r = "<<&r<<endl;//一样的
cout<<"&b = "<<&b<<" &r = "<<&r<<endl;//不一样的
return 0;
}
4.引用指针的写法
#include <iostream>
#include <cstdlib>
using namespace std;
typedef struct Node{
int data;
struct Node *next;
}node_t;
//引用指针的用法
//node_t * &r = phead;
void create_node(node_t * &r, int data){
r = (node_t *)malloc(sizeof(node_t));
r->data = data;
r->next = NULL;
}
int main(){
node_t *phead = NULL;
create_node(phead, -1);
phead->data = 100;
cout<<phead->data<<endl;
free(phead);
phead = NULL;
}
5.常引用
#include <iostream>
using namespace std;
void my_add(const int &x, const int &y){
cout<< x+y <<endl;
//x = 100;//不能通过常引用修改引用目标的值
}
int main(){
int a = 10;
int b = 20;
my_add(a, b);
int m = 520;
const int &r = m;
//r = 100;//错误的
m = 100;//但是不影响m 因为m的类型在定义时就已经确定了 是没有const的
const int &r2 = 100;//常引用可以引用常量
//int &r3 = 100;//普通的引用不能
const int &r4 = m+100;//常引用可以引用临时值
//int &r5 = m+100;//普通的引用不能
const int n = 10;
const int &r6 = n; //引用const 变量时也需要常引用
return 0;
}
6.引用做返回值
我们平时使用的函数,返回值都是一个右值;
但是引用作为返回值,返回的是一个左值;
左值:既可以放在等号左边,也可以放在等号右边的值,如变量
右值:只能放在等号右边的值,如 常量
引用做返回值时,不能返回局部变量的引用,因为局部变量占用的空间
在函数结束时,就被操作系统回收了;
可以返回全局变量的引用,或者static修饰的局部变量的引用。
#include <iostream>
using namespace std;
int &my_add(const int &x, const int &y){
//int temp = x+y;//不能返回局部变量的引用
static int temp = x+y;
return temp;
}
int main(){
int a = 10;
int b = 20;
int ret = my_add(a, b);
cout<<ret<<endl;
my_add(a, b) = 100;//引用做返回值,返回的是一个左值!!
return 0;
}
7.引用和指针的区别
1.引用必须初始化 指针可以不初始化
2.引用不可以改变指向 指针可以
3.不存在指向NULL的引用 指针可以指向NULL
4.指针在使用前需要检查合法性 引用不需要
5.可以定义指针数组、不可以定义引用数组
int a = 10,b = 20;
int *arr[2] = {&a, &b} //正确
int &arr[2] = {a, b} //错误
6.可以定义数组指针,也可以定义数组引用
int arr[2][2] = {10,20,30,40};
int (*arr_p)[2] = arr;
-----------------------------------
int arr[2] = {10,20};
int (&arr_p)[2] = arr;//错误的数组引用
int (&arr_p)[2][2] = arr;//正确的数组引用
7.可以定义指针函数,也可以定义引用函数
int *func_p(int a, int b){}
-----------------------------------
int &func_p(int a, int b){}
8.可以定义函数指针,也可以定义函数引用
int func(int a, int b){}
int (*func_p)(int a, int b);
func_p = func;
------------------------------------
int (&func_r)(int a, int b) = func;
9.可以定义指针的指针(二级指针) 不可以定义引用的引用(二级引用)
int a = 100;
int *p = &a;
int **pp = &p;
---------------------------------
int a= 100;
int &r = a;
std::cout<<“world”<