从C到C++

12 篇文章 0 订阅
2 篇文章 0 订阅

目录

1. 输入输出

1.1 输入的区别

1.2 输出的区别

3. 字符串

4. 代码风格

5. bool类型

6. 引用

7.3 C++的const_cast类型转换

7.4 使用“重新解释强制类型转化”reinterpret_cast

8. 函数重载

9. 内存分配

11. 异常处理

15. for循环

16. 从函数指针到lambda表达式 

17. 从手写轮子到各种容器


几乎99%的初学者,包括很多已经耕耘多年的大佬,都是先学习C语言,再重新学习C++,这个过程,浪费了大量时间,因为有很多内容是完全重复的。从语言特性上说,C++本身就包含C语言的所有特性的,既然如此,我们能不能直接从C语言快速提升到C++呢?毕竟,C语言入门后,不想再写C++的Hello world了哦!这篇博客,总结了从C语言基础,快速掌C++的“捷径”。
 

本片博客,要求已经掌握C语言基础用法。

1. 输入输出

1.1 输入的区别

C语言的输入

#include <stdio.h>
 
int main(void) {
	int x;
	int ret = scanf("%d", &x);
	// 输入成功,scanf返回成功输入数据的个数,这里为1
	// 输入失败,scanf返回0,例如输入a时返回0
	// 输入结束(遇到文件结束符,对于标准输入设备-键盘,按下ctrl+z),返回-1
 
	return 0;
}

C++的输入:

#include <iostream>
 
int main(void) {
	int x, y;
	std::cin >> x >> y;
	// 输入完成后,std:cin返回cin本身, 以便实现连续输入
 
	return 0;
}

注意cin的返回值,当输入结束时,可以通过类型转换为false 

#include <iostream>
 
int main(void) {
	int x;
	if (!(std::cin >> x)) {
		std::cout << "输入失败!";
	}
	
	return 0;
}

1.2 输出的区别

C语言的输出:

#include <stdio.h>
 
int main(void) {
	int x = 100;
	printf("x=%d\n", x);
 
	return 0;
}

C++的输出:

#include <iostream>
 
int main(void) {
	int x = 100;
	std::cout << "x=" << x << std::endl;
 
	return 0;
}

补充:文件名以.c结尾,很多集成开发环境(例如VS)会自动使用c语言编译器来编译,文件名以.cpp结尾,自动以c++编译器来编译。

2. 命名空间

使用C语言开发大型项目时,一定要在开发之前,做好命名约定,避免不同模块之间的标识符同名。一共常见的用法,每个模块对外使用的接口,以这个模块名作为前缀。例如调制解调器模块modem的接口:  modemInit(调制解调器的初始化), modemGetTemperature(获取调制解调器的温度)。而在C++中,可以使用命名空间来进行标识符的“隔离”。std是C++已经定义好的命令空间。

使用 using namespace 可以简化命令空间的使用。
 

#include <iostream>
 
using namespace std;
int main(void) {
	int x;
	cin >> x;   // 不需要再写成  std::cin >> x;
	cout << x;  // 不需要再写成  std::cin << x;
 
	return 0;
}

3. 字符串

C语言没有专用的字符串类型,直接使用char数组,或者char*来表示字符串。

#include <stdio.h>
#include <string.h>
 
int main(void) {
	char name[32];
	printf("您贵姓啊?");
	scanf("%s", name);
	
	strcat(name, "工");
 
	printf("你使用什么语言哦?");
	char language[16];
	scanf("%s", language); 
 
	if (strcmp(language,"C++") ==0){
		printf("%s大佬好!", name);
	}
	
	return 0;
}

C++直接使用string类型表示字符串。

#include <iostream>
#include <string>
using namespace std;
 
int main(void) {
	string str;
	cout << "您贵姓啊?";
	cin >> str; 
	str = str + "工"; 
	cout << str << ",出BUG了!";
 
	cout << "你使用什么语言哦?";
	string language;
	cin >> language;
 
	if (language == "C++") {
		cout << "大佬好!" << endl;
	}
	
	return 0;
}

4. 代码风格

5. bool类型

C语言本身,并不支持bool类型,不能直接使用,除非自己定义:

#define bool  int
#define false 0
#define true  1

或者直接包含头文件:

#include <stdbool.h>

C++可以直接使用bool类型。

6. 引用

对于C语言,把变量作为函数的参数传递给函数后,如果需要在这个函数内部修改这个变量的值,就需要把对应的参数定义为指针。如果这个变量本身就是一个指针,就需要把对应的参数定义为二级指针。而在C++中,只需要使用引用类型就可以实现。

C语言实现:

C++的引用:

#include <iostream>
 
void addSalary(int& salary) {
	salary += 1000;
}
 
int main(void) {
	int salary = 20000;
 
	addSalary(salary);
 
	std::cout << "salary=" << salary << std::endl;
	return 0;
}

引用在本质上,也是通过指针实现的,但引用是由编译器在底层用指针来实现的,已经对C++程序员做了透明化处理,我们已经不需要关注底层的实现细节, 直接理解为“引用”就是被引用变量的“别名”。
7. 强制类型转换
7.1 C语言的强制类型转换

C语言的强制类型转换,非常简单粗暴,不管你同不同意,乐不乐意,直接转。
 

#include <stdio.h>
 
struct girl {
	int age;
	int size[3]; //三维
	char name[16];
};
 
struct boy {
	int age;
	int weight; //体重:kg
	int height; //身高:cm
	char name[16];
};
 
void showGirl(struct girl* girl) {
	printf("\n姓名:%s\n三维:%d,%d,%d\n年龄:%d\n", 
		girl->name, girl->size[0], girl->size[1], girl->size[2], girl->age);
}
 
void showBoy(struct boy* boy) {
	printf("\n姓名:%s\n身高:%d\n体重:%d\n年龄:%d\n", 
		boy->name, boy->height, boy->weight, boy->age);
}
 
int main(void) {
	struct girl girl1 = { 20, {80, 70, 90}, "小凤" };
	struct boy boy1 = { 22, 80, 178, "老王" };
 
	// 正常输出
	showGirl(&girl1);
	showBoy(&boy1);
 
	// 使用强制类型转化输出不可预期的结果(实际上c语言编译器不需要使用代码强转)
	showGirl((struct girl*)&boy1); 
 
	return 0;
}

执行效果如下:

7.2 C++的静态强制类型转换 static_cast

	struct girl girl1 = { 20, {80, 70, 90}, "小凤" };
	struct boy boy1 = { 22, 80, 178, "老王" };
 
	// 使用静态强制类型转换,boy1转“伪娘”失败!(但是可以使用C语言的强制类型转换成功)
	struct girl* p = static_cast<struct gilr*>(&boy1); 

 正因为转换失败,所以更安全!在C++中,一般的类型转换,建议使用 static_cast

7.3 C++的const_cast类型转换

C++中不能直接使用自由指针指向const常量:

	const int x = 10;
	int* p = &x; //错误!

 此时只要使用const_cast去除const属性即可。

	const int x = 10;
	int* p = const_cast<int*>(&x);  //使用const_cast去除const属性
	*p = 20; //不会报错,(但实际上并没有被修改)
 
	printf("%d\n", x);  // 10
	printf("%d\n", *p); // 20

7.4 使用“重新解释强制类型转化”reinterpret_cast

#include <iostream>
using namespace std;
 
int main()
{
	int num = 0x00636261;//0x61是字符'a'的ASCII码
	//char* p = static_cast<char*>(&num); //使用静态强制类型转换失败
	char* p = reinterpret_cast<char*>(&num); //使用“重新解释强制类型转化”
	cout << p << endl;
	return 0;
}

其实这里直接使用C语言方式的强制类型转换,也能起到类似的效果。
7.5 使用动态类型转换dynamic_cast

dynamic_cast 用于具有共同祖先类的各个类层次间的向上和向下转换,但只适用于含有虚函数的类,否则讲导致编译失败。使用dynamic_cast转换失败时返回NULL,可以根据是否为空来判定是否转换成功。
 

#include <iostream>
 
using namespace std;
 
class Father {
public:
	virtual void play() { std::cout << "K歌" << std::endl; }
private:
	int money;
};
 
class Son :public Father {
public:
	virtual void play() { std::cout << "吃鸡" << std::endl; }
	void work() { std::cout << "working in " << addr << std::endl; }
private:
	string addr = "China";
};
 
int main(void) {
	//在实际项目开发中,往往并不知道p1和p2到底指向的是Father对象还是Son对象
	//比如,很多对象是根据程序的运行情况,比如用户的交互情况来创建父类或者子类对象,最后都由父类指针所指向
	Father* p1 = new Father;
	Father* p2 = new Son;
	Son* s;
 
	s= (Son*)p2;
	s->work();  // OK
 
	//危险!将导致崩溃!直接使用C语言方式的强制类型转换是不安全的
	//s = (Son*)p1;
	//s->work();  
 
	// 使用静态类型转换,竟然转换成功!但依旧是不安全的!将导致崩溃
	//s = static_cast<Son*>(p1);
	//s->work();
	
	// 使用动态类型转换,转换事变后,返回NULL
	s = dynamic_cast<Son*>(p1);
	if (s) {
		s->work();
	} else {
		std:cout << "转化失败!" << std::endl;	
	}
 
	return 0;
}

8. 函数重载

C语言不支持函数重载。

// demo.c
 
#include <stdio.h>
 
int add(int a, int b) {
	return a + b;
}
 
int add(int a, int b, int c) { //编译报错!
	return a + b + c;
}
 
int main(void) {
	printf("%d", add(3, 5, 8));
	return 0;
}

 C++支持函数重载哦

//demo.cpp
#include <stdio.h>
 
int add(int a, int b) {
	return a + b;
}
 
int add(int a, int b, int c) { //实现函数重载
	return a + b + c;
}
 
int main(void) {
	printf("%d", add(3, 5, 8));
	return 0;
}

9. 内存分配

C语言内存分配: malloc 和 free

C++内存分配:new 和 delete

11. 异常处理

C语言的异常处理:

#include <stdio.h>
#include <assert.h>
 
 
int div(int a, int b) {
	assert(b != 0);
	return a / b;
}
 
int main(void) {
	printf("%d\n", div(100, 0));
	return 0;
}

 C++异常处理:

#include <iostream>
using namespace std;
 
double division(int a, int b) {
    if (b == 0) {
        throw "Division by zero condition!";  //抛出异常
    }
    return (a / b);
}
 
int main() {
    int x = 50;
    int y = 0;
    double z = 0;
 
    try {
        z = division(x, y);
        cout << z << endl;
    }
    catch (const char* msg) {
        cerr << msg << endl;
    }
 
    return 0;
}

12. 结构体和类

C语言的结构体,只含有数据,C++的类,是一个加强版的“结构体”,主要增加了以下特性:
1. 使用了面向对象思想,可以继承和派生(父类、子类、孙子类)
2. 使用了权限控制(public,  private, protected)
3. 使用了构造函数和析构函数
13. 文件操作

C++使用IO流的方式操作文件,实际效果和C语言的文件操作相同。
14. auto自动类型推导
 

    int x = 100;
    auto y = 100;

auto在对C++容器的迭代器操作时,非常频繁,也非常方便。 

15. for循环

#include <stdio.h>
#include <iostream>
 
int main() {
    int score[10] = {90, 95, 88, 73, 84, 100, 50, 91, 80, 65};
 
    // C语言用法,C++老式用法
    for (int i = 0; i < 10; i++) {
        printf("%d ", score[i]);
    }
    printf("\n");
 
    // C++新方式1
    for (auto x : score) {
        printf("%d ", x);
        x++; //x拷贝自score, x改变,对score数组无意向
    }
    printf("\n");
 
   
    // C++新方式2
    for (auto &x : score) {
        printf("%d ", x);
        x++; //x是对score中成员的引用, x改变,score数组被改变
    }
    printf("\n");
 
    // C++新方式3
    for (const auto& x : score) {
        printf("%d ", x);
        //x++; //不能改变x
    }
    printf("\n");
 
    return 0;
}

16. 从函数指针到lambda表达式 

#include <iostream>
 
void hello() {
	std::cout << "hello world" << std::endl;
}
 
// 使用函数指针作为参数
void test(void(*p)()) {
	p();
}
 
int main(void) {
	//最简单的lambda表达式
	auto f = [] {
		std::cout  << "你能看出我是一个函数吗?" << std::endl;
	};
 
	f(); //lambda表达式也可以直接调用
 
	test(hello); //使用函数指针
	test(f);     //使用lambda表达式
 
	return 0;
}

17. 从手写轮子到各种容器

C++常用容器:vector, list, deque双端队列容器), set, map, stack(栈), queue(队列容器).


今天的分享就到这里了,大家要好好学C语言/C++哟~

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)加下方群获取哦~
C语言C++编程学习交流圈子,QQ群:763855696【点击进入】


C语言从入门到精通(C语言入门C语言教程C语言零基础C语言基础C语言学习C

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值