一文带你认识C++和C的区别

133 阅读11分钟

1. 认识C++和C的区别

认识C++和C的区别

C++最简单的程序

头文件包含问题
#include <iostream>		//不需要.h 直接包含
int main()
{
	return 0;    
}
  • 创建的项目源文件后缀是.cpp

  • 头文件的包含不同

    • 不需要.h 直接包含

    • C语言的标准库头文件

      • 依然按照原来方式包含,一定程序C++兼容C语言

      • C++包含方式: c+原来的头文件,去掉.h

#include <ctime>
  • 自己的写头文件: 按照C语言教的方式包含
完整代码
#include <iostream>
#include <stdio.h>
#include <ctime>
#include <cstdlib>
#include "myhead.h"			//自己写的依旧是按照原来方式
int main() 
{
	printf("C语言的函数!\n");
	return 0;
}

C++命名空间

什么是命名空间

可以提高标识符使用,可以避免命名污染

如何创建命名空间

namespace 空间名
{
	//变量
    //函数
    //结构体
    //类
}
//用namespace 声明一个东西
怎么访问命名空间
  • 作用域分辨符

    • 访问空间中的成员: 空间名::成员名

    • 用来区分全局变量和局部变量

      • 全局变量
#include <iostream>
#include <cstdio>
namespace MM 
{
	int age = 1;
	void print() 
	{
		printf("MM\n");
	 }
}
namespace Boy 
{
	int age = 2;
}
int g_num = 1001;
int main() 
{
	printf("%d\n", MM::age);
	printf("%d\n", Boy::age);
	int g_num = 1;
	printf("全局变量:%d\n", ::g_num);
	return 0;
}

  • 省略前缀的方式去调用
//using namespace  空间名;		//要省略的空间名
//注意点:有作用域
#include <iostream>
#include <cstdio>
namespace MM 
{
	int age = 1;
	void print() 
	{
		printf("MM\n");
	 }
}
namespace Boy 
{
	int age = 2;
}
int g_num = 1001;
int main() 
{
	printf("%d\n", MM::age);
	printf("%d\n", Boy::age);
	int g_num = 1;
	printf("全局变量:%d\n", ::g_num);
	MM::print();
	using namespace MM;				//省略前缀的调用方式
	print();
	using namespace Boy;
	//printf("%d\n", age);		    //二义性问题:有两个选择,不知道找谁
	printf("%d\n", Boy::age);
	printf("%d\n", MM::age);
	return 0;
}

命名空间嵌套
namespace A 
{
	int a=1;
	namespace B 
	{
		int b = 1;
	}
}
void test()
{
	//剥洋葱
	A::a = 1;
	A::B::b = 2;
	using namespace A::B;
	b = 3;
}
先声明后实现
//其他写法: 先声明后实现的一种写法
namespace Data
{
	void print();
	struct student;
}

//必须空间名限定
void Data::print() 
{

}
struct Data::student 
{
	int age;
	int num;
};

标准的命名空间std
  • C++所有的函数和类都是属于标准命名空间

    • 不写using namespace std; 意味着所有C++标准库中的东西都需要加上std::
using namespace std;				//习惯性的操作

C++函数新思想

函数重载
什么是函数重载

C++允许同名不同参数的函数存在,C语言不允许同名函数存在

不同参数的三个体现
  • 数目不同

  • 类型不同

  • 顺序不同:前提条件是存在不同类型

#include <iostream>
using namespace std;
//类型不同
int Max(int a, int b) 
{
	return a > b ? a : b;
}
float Max(float a, float b) 
{
	return a > b ? a : b;
}
//顺序不同
// error C2084: 函数“int Max(int,int)”已有主体
//int Max(int b, int a) 
//{
//
//}
void  print(int a, char c) 
{

}
void print(char a, int c) 
{

}
//数目不同
void print(int a, int b, int c) 
{

}
//想当然了
//double就是末尾加个d  错误的
//char就是加个c	错误的
int main() 
{
	printf("%d\n", Max(1, 2));
	printf("%.1f\n", Max(1.1f, 2.2f));   //错误,C++对于类型要求比C语言严格
	1L;		//long
	1.1f;	//float
	1u;	    //unsiged;
	//默认的小数是double;
	return 0;
}

函数重载和函数返回值一点毛线关系都没有。

函数缺省
什么是函数缺省

函数缺省就是给形参赋初始值,当不传参的时候使用的是默认值

函数缺省规则
  • 只能从右往左缺省,中间不能有空着的

  • 多文件中,.h文件缺省了,cpp不需要缺省(声明做了缺省,实现就不需要缺省)

缺省的好处

实现函数的不同形态的调用,针对不同需求做不同实现

//loadimage

//putimage


#include <iostream>
using namespace std;
//函数缺省
void printData(int a=1, float b = 1.11f, double c=1.11 , char d = 'A') 
{
	printf("%d\t%f\t%lf\t%c\n", a, b, c, d);
}

int main() 
{
	printData();					//所有形参都是默认值
	printData(9);					//a=9,其他值用默认值
	printData(9, 2.22f);			//a=9 b=2.22 其他默认值
	printData(9, 2.22f, 9.9);		//a=9,b=2.22 c=9.9 其他默认值
	printData(9, 2.22f, 9.9,'D');	//所有的值用的是传入的值
	return 0;
}

C++标准输入和输出

注意点: 目前大家学会即可,不需要问为什么!!!!!后续在IO流会详细讲这些

标准输出
  • cout + << 一起完成的

  • 换行: endl替换"\n"

#include <iostream>
using namespace std;			 //缺省std前缀的
struct MM 
{
	char name[20];
	int age;
	int num;
};
int main() 
{
	//单个数据输出
    //没有写using namespace std; 必须加前缀
	std::cout << "ILoveyou";		
	cout << 1;
	//多个数据的输出
	cout << "\n";
	cout << "姓名\t" << "年龄\t" << "编号\n";
	struct MM mm = { "mm",18,1001 };
	cout << mm.name << "\t" << mm.age << "\t" << mm.num << "\n";
	//和上面一行代码效果一样
	cout << mm.name << "\t";
	cout << mm.age << "\t";
	cout << mm.num << "\n";
	cout << endl;				//等效:cout<<"\n";
    //一样的是std命名空间中的
	std::cout << std::endl;		
	return 0;
}
标准输入
  • cin + >> 一起完成

  • 输入不需要任何的格式控制字符

#include <iostream>
using namespace std;			 //缺省std前缀的
struct MM 
{
	char name[20];
	int age;
	int num;
};
int main() 
{
	cout << "请输入一个整数:";
	int num;
	cin >> num;			//变量名
	cout << num << endl;
	cout << "请输入一个字符串:";
	char str[20];
	while (getchar() != '\n');		//存在跳过显现:清空缓冲区
	//setbuf(stdin, NULL);				//影响汉字输入,汉字的文件操作出现问题	
	//fflush(stdin);					//C++中已经淘汰了,有时候使用没有效果
	cin >> str;							//数组名
	cout << str << endl;
	cout << "input num and str:";
	cin >> num >> str;
	cout << num << "\t" << str << endl;
	cout << "input name,age,num:";
	struct MM temp;
	cin >> temp.name >> temp.age >> temp.num;
	cout << "姓名\t年龄\t编号" << endl;
	cout << temp.name << "\t" << temp.age << "\t" << temp.num << endl;
	return 0;
}

新基本数据类型

bool类型
  • 占用内存是1个字节

  • 打印出来的值是: 0或者1 非零值表示成立

  • 通常用的是false和true做初始化

#include <iostream>
void testBool()
{
	bool bNum = 5;
	std::cout << bNum << std::endl;
	//一般是会用都用关键字初始化
	bNum = false;
	bNum = true;
	//用途:
	//做开关
	//做标记-->查找类的操作
	//做函数返回值
	while (true);	//死循环
}
int main() 
{
	testBool();
	return 0;
}

引用类型

希望同学把引用类型理解为一个起别名的用法

  • 左值引用

    • 当做函数参数: 直接修改实参,防止拷贝本产生

    • 当做返回值: 增加左值使用

    • const属性限定问题

  • 右值引用

    • 给右值起别名

    • 当做函数参数: 函数只能传入右值

      • 想要传入左值,使用move函数移动
#include <iostream>
using namespace std;
//No.2  引用类型
void Modify(int& x)  //int& x=b;
{
	x = 9999;
}
//返回引用等效返回一个变量
//warning C4172: 返回局部变量或临时变量的地址: a
int g_num = 1001;
int& getValue() 
{
	return g_num;
}
int getData() 
{
	return g_num;
}
void printString(const char* str)  //char* str="Iloveyou"
{
	cout << str << endl;
}
void modifyNum(const int& num) 
{
	//num++;  //常引用不能做++
	cout << num << endl;
}
void modifyNum2(int&& num)  //只能传入右值
{
	num++;					//提供修改接口
	cout << num << endl;
}

void testNew() 
{
	int a = 1;
	int& b = a;
	b = 1001;
	cout << a << endl;
	//当做函数返回值:增加左值使用好处
	//当做函数参数:防止拷贝本的产生
	Modify(b);
	cout << a << endl;
	//getData() = 1003;  错误,返回是一个值,不是一个变量,不能充当运算符左值
	getValue() = 9999;   //g_num=9999;
	cout << g_num << endl;
	//常量起别名
	//C++对于const属性要求更为严格
	//1.用常引用
	const int& xx = 13;
	cout << xx << endl;
	//error C2440: “初始化”: 无法从“const char [9]”转换为“char *”
	const char* pstr = "ILoveyou";
	printString("ILoveyou");
	char array[10] = "LLLL";
	printString(array);
	//常引用不能修改
	//2.右值引用 &&  --->提供修改接口
	int&& yy = 134;
	yy = 55;
	const int c_num = 112;  //常属性的变量,依旧是左值
	//int&& zz = c_num;		//错误
	modifyNum(1);
	modifyNum2(23);
	//左值变成右值
	int data = 1001;
	int&& data2 = move(data);       //移动函数:把左值变成右值
	int value = 1234;
	//modifyNum2(value);			//错误,用右值引用当做函数参数,不能传左值
	modifyNum2(move(value));        //移动语义(完美转发)
}
int main() 
{
	testNew();
	return 0;
}

C++结构体类型

  • 类型名不在需要struct关键字了

  • C++结构体可以给成员直接赋初始值

  • C++结构体可以包含函数

  • 其实C++结构体的处理就是按照类的方式处理(后续在意)

    • 用了构造函数时候C++结构体和C语言结构体处理方案是完全不同的
#include <iostream>
using namespace std;
//描述的是事物特征和行为
struct MM 
{
	char name[20]="MM";
	int age=111;
	int num=1001;
	void initData(const char* str, int age, int num);		//在结构体声明
	void printData() 
	{
		cout << name << "\t" << age << "\t" << num << endl;
	}
};
//在外面实现,必须结构体名限定
void MM::initData(const char* str,int age,int num) 
{
	strcpy_s(name,20, str);
	//同名问题
	MM::age = age;
	MM::num = num;
}
int main() 
{
	//No.1 类型不需要struct
	MM mm;
	//cout << mm.name << "\t" << mm.age << "\t" << mm.num << endl;
	mm.printData();
	MM mm2 = { "mm2",18,1030 };
	//cout << mm2.name << "\t" << mm2.age << "\t" << mm2.num << endl;
	mm2.printData();
	mm2.initData("小芳", 18, 1004);
	mm2.printData();
	return 0;
}

C++枚举类型

#include <iostream>
using namespace std;
enum State {Open,Close};
enum class Color
{
	Red,
	Blue
};
void print(int state)
{
	cout << state << endl;
}
void printEnum(Color color) 
{
	//cout << color << endl;  不能直接打印
}
void testEnum() 
{
	print(1);
	print(Open);
	//C++的枚举类型不能当做一个简单的int类型
	//print(Color::Red);  //访问必须要用枚举类型名限定
	printEnum(Color::Red);
}
int main() 
{
	testEnum() 
	return 0;
}

C++string类型

C++string本身是一个类,所以大家本节课只要学会使用即可,不需要问问什么

  • 头文件: #include

    • 注意点和cstring区别,这个是C语言头文件
  • 没有用using namespace std ; string类型需要改为std::string

  • 掌握string常用方式

    • 创建方式

    • 基本操作(比较,连接)

    • 转C语言char*

微软帮助文档:basic_string 类 | Microsoft Docs

#include <iostream>
#include <string>
using namespace std;
int main() 
{
	//std::string str;
	//No.1创建
	string str1;
	str1 = "ILoveyoudsfasdfasdfasdfasdfasd";
	cout << str1 << endl;
	string str2 = "ILoveyousdfsdafads";
	cout << str2 << endl;
	string str3(str2);
	string str4 = str2;
	cout << str3 << endl;
	cout << str4 << endl;
	//No.2 基本操作
	cout << (str3 == str4) << endl;
	cout << (str3 >= str4) << endl;

	string password;
	cin >> password;
	cout << password;
	//原理是:运算符重载 后面会讲
	//比较直接比
	if (password == string("12345")) 
	{
		cout << endl << "密码正确" << endl;
	}
	int a = (int)1.3;		//C语言强制类型转换
	int b = int(1.34);		//C++强制类型转换
	//连接直接加法
	string name = "张三";
	string info = name + "很帅";
	cout << info << endl;
	//上述复杂的用法
	cout << info.compare(name) << endl;  //和strcmp 返回值一样
	cout << info.append(name) << endl;

	//下标的方式访问
	cout << info.length() << endl;	   //当前长度
	cout << info.size() << endl;
	for (int i = 0; i < info.length(); i++) 
	{
		cout << info[i];
	}
	cout << endl;
	for (int i = 0; i < info.length(); i++)
	{
		cout << info.at(i);
	}
	cout << endl;
	cout << info.capacity() << endl;   //容量
	//和C语言string.h有区别的 char* 
	// 不能用%s的方式打印
	//printf("%s\n", info);
	// 图形库中传char* 函数 都不能直接用string类型
	//提供两个函数: c_str() data();
	printf("%s\n", info.c_str());
	printf("%s\n", info.data());
	return 0;
}

C++自动推断类型

  • auto类型

  • decltype类型

#include <iostream>
using namespace std;
struct MM 
{
	int age;
};
MM g_MM = { 12 };
MM* createMM() 
{
	MM* p=&g_MM;
	return p;
}
int Max(int a, int b) 
{
	return a > b ? a : b;
}
void print(int(*Max)(int, int), int a, int b) 
{
	cout << Max(a, b) << endl;
}
void printData(int(*)(int, int), int, int) 
{
	cout << "另一个函数" << endl;
}

int main() 
{
	//auto 类型自动推断: 一定要有赋值 所以不能单独定义变量
	//auto a;  没有赋值 推断不出来
	auto a = 1;				//int 
	a = 134;
	auto pMM = createMM();
	cout << pMM->age << endl;
	auto pFunc = print;		//void (*)(int(*)(int, int), int , int ) 
	pFunc(Max, 1, 3);
	pFunc = printData;
	pFunc(Max, 1, 3);
	int* p = nullptr;			//新的空 等效C语言NULL
	//decltype 不需要赋值

	decltype(123) num = 123;    //decltype(123) 表示一个int类型
	//函数指针必须取地址
	decltype(&print) ppFunc;
	ppFunc = printData;
	//推断一个int
	decltype(num) Num = num;
	decltype(&num) pNum = &num;	//当你们用的时候,不知道类型,推断定义变量去赋值
	return 0;
}

C++动态内存申请

C申请的内存是自由存储区的,C语言的堆区内存,所以C类的对象内存不能用malloc申请

// IMAGE *

  • new申请内存

    • 申请单个变量内存

    • 申请一段内存

    • 申请内存可以手动初始化

    • 申请内存后可以再分配

  • delete释放内存

    • 释放单个变量内存:delete 指针名;

    • 释放一段变量内存: delete[] 指针名;

#include <iostream>
using namespace std;
struct MM 
{
	char name[20];
	int age;
	int num;
};
void testOne() 
{
	int* pInt = new int;
	*pInt = 123;
	cout << pInt[0] << endl;
	delete pInt;
	pInt = nullptr;
	char* pc = new char;
	delete pc;

	int* pNum = new int(1234);	//申请并且初始化
	cout << pNum[0] << endl;
	delete pNum;
	MM* pMM = new MM({ "name",12,1101 });
	cout << pMM->name << "\t" << pMM->age << "\t" << pMM->num << endl;
}
void testTwo() 
{
	//一段内存的申请
	int size = 4;
	int* pArray = new int[size];		//int pArray[4];
	MM* pMM = new MM[4];				//MM pMM[4];
	delete[] pArray;
	delete[] pMM;
	pArray = nullptr;
	pMM = nullptr;

	int* pNum = new int[4]{ 1, 2, 3, 4 };
	for (int i = 0; i < 4; i++) 
	{
		cout << pNum[i] << "\t";
	}
	cout << endl;
	delete[] pNum;
	pNum = nullptr;
}
void testThree() 
{
	char* pMem = new char[1024];
	//在原来上面拿个20字节存整数
	int* pInt = new(pMem + 0) int[5]{ 1,2,3,4,5 };
	//在原来上面拿出20个存字符
	char* pChar = new(pMem + 20) char[20]{"ILoveyou"};
	//等效:char* pChar = new(pInt + 5) char[20]{"ILoveyou"};
	delete[] pMem;
	pMem = nullptr;
}
int main() 
{
	testOne();
	testTwo();
	testThree();
	return 0;
}