【C++】从C语言到C++学习指南

news2024/11/28 1:39:16

如果你也是从C语言一路过来的,那么请一起看下去吧!

文章目录

  • 面型对象程序设计
  • C++基础
    • C和C++一些语法区别
    • C++在非对象方面对C语言的扩充
    • C++的一些标准(兼容旧标准)

首先,在C++的学习中,我们要时刻清醒一点:虽然C++与C语言有很大区别,但C++是C语言的扩充

说到C++和C语言的区别,那也是面向对象和面向过程的区别,这时你的老师可能会这么给你讲:

在这里插入图片描述

可是学了C语言没学过C++的人发问了:我们在学面向过程设计的时候,说“数据和操作往往都是分离的”,数据是米饭,操作是米饭上盖的菜,既然如此面向过程那不应该是盖饭吗?而面向对象具有封装的特点更是炒饭呀!(老师气的脸都绿了)

只有当你亲口尝了这两种饭菜,你才会知道盖饭中的菜是什么米是什么,炒饭中的菜是什么米是什么,以及他们的口味。所以,当你正确的理解了这个比喻,你便能真正认识C语言与C++,面向过程和面向对象,那么请跟随我一起去寻找我们的答案吧~

面型对象程序设计

面向过程是这样的:

img

一个程序是一道菜,面向过程这道菜的特点是:先从整体角度全面看待问题,然后列出解决问题需要的步骤,再逐步去完善。

面向对象是这样的:

img

面向对象这道菜有两个主要的结构特点:①程序一般由类的定义(属性)和类的使用(行为)两部分组成;②程序中的一切都是通过向对象发送消息来实现的,对象接收到消息后,启动有关方法完成相应的操作。

  • 对象:描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体。对象可认为是数据+操作。
  • :类是具有相同的数据和相同的操作的一组对象的集合。
  • 消息传递:对象之间的交互。
  • **方法:**对象实现的行为称为方法

面向对象程序设计的基本特征:抽象、封装、继承、多态。


理清了面向对象和面向过程之间的区别后,然我们来了解一下——从C语言到C++~

C++基础

C++的产生和特点

C++是美国贝尔实验室的Bjarne Stroustrup博士在C语言的基础上,弥补了C语言存在的一些缺陷,增加了面向对象的特征,于1980年开发出来的一种面向过程性与面向对象性相结合的程序设计语言。最初他把这种新的语言称为“含类的C”,到1983年才取名为C++。

相比C语言,C++的主要特点就是增加了面向对象机制!

一个简单的C++示例程序

#include<iostream>                 //编译预处理命令
using namespace std;               //使用命名空间

void Log(const char* message) {    //函数定义
	cout << message << endl;
}

int main() {
	Log("Hello World!");
	cin.get();
}

C和C++一些语法区别

1.三目运算符:在C语言中返回的是一个常量,是不能被赋值的;而C++中返回的是变量,可以被赋值

2.C++中的函数必须要写返回值类型

3.在全局下,C++不允许int a;int a=10;等这种重定义二义性操作

4.在C++中不要返回局部变量或临时变量的地址,虽然C++能够运行变量出作用域之后再使用一次,即C++允许在代码块中的任何地方声明局部变量。

5.C语言中const修饰的变量不能定义数组大小,而C++中可以

const int a=10;
float arr[a];
12

6.C++中定义结构体类型变量可以不用写结构体类型名

7.关于C语言有没有bool类型:C语言的布尔类型(bool)

C++在非对象方面对C语言的扩充

(1)输入和输出

int i;
float f;
cin >> i;
cout << f;
------------
scanf("%d", &i);
printf("%f", f);
----------------
连续读入
cin >> a >> b >> c;

【cin】

  • 在默认情况下,运算符“>>”将跳过空白符,然后读入后面与变量类型相对应的值。因此,给一组变量输入值时可用空格符、回车符、制表符将输入的数据间隔开。
  • 当输入字符串(即类型为string的变量)时,提取运算符“>>”的作用是跳过空白字符,读入后面的非空白字符,直到遇到另一个空白字符为止,并在串尾放一个字符串结束标志‘\0’。

(2)const修饰符

在C语言中,习惯使用#define来定义常量,例如#define PI 3.14,C++提供了一种更灵活、更安全的方式来定义常量,即使用const修饰符来定义常量。例如const float PI = 3.14;

const可以与指针一起使用,它们的组合情况复杂,可归纳为3种:指向常量的指针、常指针和指向常量的常指针。

  • 指向常量的指针:一个指向常量的指针变量。

    const char* pc = "abcd";
    该方法不允许改变指针所指的变量,即
        pc[3] = ‘x';   是错误的,
    但是,由于pc是一个指向常量的普通指针变量,不是常指针,因此可以改变pc所指的地址,例如
        pc = "ervfs";
    该语句付给了指针另一个字符串的地址,改变了pc的值。
    123456
    
  • 常指针:将指针变量所指的地址声明为常量

    char* const pc = "abcd";
    创建一个常指针,一个不能移动的固定指针,可更改内容,如
        pc[3] = 'x';
    但不能改变地址,如
        pc = 'dsff';  不合法
    12345
    
  • 指向常量的常指针:这个指针所指的地址不能改变,它所指向的地址中的内容也不能改变。

    const char* const pc = "abcd";
    内容和地址均不能改变
    12
    

说明:

  1. 如果用const定义整型常量,关键字可以省略。即 const in bufsize = 100const bufsize = 100等价;
  2. 常量一旦被建立,在程序的任何地方都不能再更改。
  3. 与#define不同,const定义的常量可以有自己的数据类型。
  4. 函数参数也可以用const说明,用于保证实参在该函数内不被改动。

(3)void型指针

void通常表示无值,但将void作为指针的类型时,它却表示不确定的类型。这种void型指针是一种通用型指针,也就是说任何类型的指针值都可以赋给void类型的指针变量

需要指出的是,这里说void型指针是通用指针,是指它可以接受任何类型的指针的赋值,但对已获值的void型指针,对它进行再处理,如输出或者传递指针值时,则必须再进行显式类型转换,否则会出错。

    void* pc;
    int i = 123;
    char c = 'a';
    pc = &i;
	cout << pc << endl;         //输出指针地址006FF730
	cout << *(int*)pc << endl;  //输出值123
    pc = &c;
	cout << *(char*)pc << endl; //输出值a

(4)内联函数

在函数名前冠以关键字inline,该函数就被声明为内联函数。每当程序中出现对该函数的调用时,C++编译器使用函数体中的代码插入到调用该函数的语句之处,同时使用实参代替形参,以便在程序运行时不再进行函数调用。引入内联函数主要是为了消除调用函数时的系统开销,以提高运行速度。

说明

  • 内联函数在第一次被调用之前必须进行完整的定义,否则编译器将无法知道应该插入什么代码
  • 在内联函数体内一般不能含有复杂的控制语句,如for语句和switch语句等
  • 使用内联函数是一种空间换时间的措施,若内联函数较长,较复杂且调用较为频繁时不建议使用
#include <iostream>
using namespace std;

inline double circle(double r)  //内联函数
{
	double PI = 3.14;
	return PI * r * r;
}

int main() 
{
	for (int i = 1; i <= 3; i++)
		cout << "r = " << i << " area = " << circle(i) << endl;
	return 0;
}

使用内联函数替代宏定义,能消除宏定义的不安全性

(5)带有默认参数值的函数

当进行函数调用时,编译器按从左到右的顺序将实参与形参结合,若未指定足够的实参,则编译器按顺序用函数原型中的默认值来补足所缺少的实参。

void init(int x = 5, int y = 10);
init (100, 19);   // 100 , 19
init(25);         // 25, 10
init();           // 5, 10
1234
  • 在函数原型中,所有取默认值的参数都必须出现在不取默认值的参数的右边

    int fun(int a, int b, int c = 111);
    1
    
  • 在函数调用时,若某个参数省略,则其后的参数皆应省略而采取默认值。不允许某个参数省略后,再给其后的参数指定参数值。

(6)函数重载

在C++中,用户可以重载函数。这意味着,在同一作用域内,只要函数参数的类型不同,或者参数的个数不同,或者二者兼而有之,两个或者两个以上的函数可以使用相同的函数名

#include<iostream>
//以下函数均构成重载
int plus(int a, int b) {
	return a + b;
}
int plus(int a, int b, int c) {
	return a + b + c;
}
double plus(double a,double b) {
	return a + b;
}
double plus(int a, double b) {
	return a + b;
}
double plus(double a, int b) {
	return a + b;
}
int main() {
	std::cout << plus(2, 3) << std::endl;
	std::cout << plus(1,2,3) << std::endl;
	std::cout << plus(2.5, 5.3) << std::endl;
	std::cout << plus(3,4.5) << std::endl;
	std::cout << plus(3.3,6) << std::endl;
}

说明:

  • 调用重载函数时,函数返回值类型不在参数匹配检查之列。因此,若两个函数的参数个数和类型都相同,而只有返回值类型不同,则不允许重载。

    int mul(int x, int y);
    double mul(int x, int y);
    12
    
  • 函数的重载与带默认值的函数一起使用时,有可能引起二义性

    int fun(int a){};
    int fun(float a){};
    

从函数重载的重载条件来看,构成重载,编译不会有问题,但在调用时,如果调用方式如:fun(2.3);

由于在C/C++中的浮点型常量默认是double类型,而double类型既可以给int型变量赋值,又可以给float型变量赋值

赋值兼容(隐式类型转换)所导致的函数重载二义性问题
→解决方法
int fun(double a){}加入新的重载函数,使得类型有确定的调用方式,不存在赋值兼容

fun((int)2.3);明确函数调用时的参数类型,可以使用强制类型转换

(7)作用域标识符::

通常情况下,如果有两个同名变量,一个是全局的,另一个是局部的,那么局部变量在其作用域内具有较高的优先权,它将屏蔽全局变量。

如果希望在局部变量的作用域内使用同名的全局变量,可以在该变量前加上“::”,此时::value代表全局变量value,“::”称为作用域标识符。

#include <iostream>
using namespace std;

int value;   //定义全局变量value

int main() 
{
	int value;  //定义局部变量value
	value = 100;
	::value = 1000;
	cout << "local value : " << value << endl;
	cout << "global value : " << ::value << endl;
	return 0;
}

(8)强制类型转换

可用强制类型转换将不同类型的数据进行转换。例如,要把一个整型数(int)转换为双精度型数(double),可使用如下的格式:

int i = 10;
double x = (double)i;int i = 10;
double x = double(i);
12345

以上两种方法C++都能接受,建议使用后一种方法。

(9)new和delete运算符

程序运行时,计算机的内存被分为4个区:程序代码区、全局数据区、堆和栈。其中,堆可由用户分配和释放。C语言中使用函数malloc()free()来进行动态内存管理。C++则提供了运算符newdelete来做同样的工作,而且后者比前者性能更优越,使用更灵活方便。

指针变量名 = new 类型
    int *p;
    p = new int;
delete 指针变量名
    delete p;
12345

下面对new和delete的使用再做一下几点说明:

  • 用运算符new分配的空间,使用结束后应该用也只能用delete显式地释放,否则这部分空间将不能回收而变成死空间。

  • 在使用运算符new动态分配内存时,如果没有足够的内存满足分配要求,new将返回空指针NULL)。

  • 使用运算符new可以为数组动态分配内存空间,这时需要在类型后面加上数组大小。

    指针变量名 = new 类型名[下标表达式];
    int *p = new int[10];
    12
    

    释放动态分配的数组存储区时,可使用delete运算符。

    delete []指针变量名;
    delete p;
    12
    
  • new 可在为简单变量分配空间的同时,进行初始化

    指针变量名 = new 类型名(初值);
    int *p;
    p = new int(99);
    ···
    delete p;
    

(10)引用

引用reference)是C++对C的一个重要扩充。变量的引用就是变量的别名,因此引用又称别名

真实的数据类型 &引用名 = 已定义的变量名

引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。实际上,编译系统使引用和其代表的变量具有相同的地址。

  • 引用并不是一种独立的数据类型,它必须与某一种类型的变量相联系。在声明引用时,必须立即对它进行初始化,不能声明完成后再赋值。

  • 为引用提供的初始值,可以是一个变量或者另一个引用。

  • 引用的类型必须和其所对应的变量的类型相同

  • 对引用的操作和对引用对应的变量的操作是完全等价的

  • 不允许建立void类型的引用

  • 不能建立引用的数组

  • 可以用const对引用加以限定,不允许改变该引用的值,但是它不阻止引用所代表的变量的值。

#include<iostream>
using namespace std;
int main() {
	int a = 8;
	int& ref_a = a;
	ref_a++;
	cout << a << endl;//9
}
//上面代码输出a和ref_a的值相同,地址也相同。

引用就是指针的语法糖(syntax sugar)
我们为什么要使用引用呢?我们干嘛要起个别名而不直接用真名呢?
假设我们想通过调用一个函数来实现一个整型变量的自增,有下面3种传递方式:
值传递:形参的改变无法改变实参的值

void fun(int x) {
	x++;
}
int main() {
	int a = 8;
	fun(a);
	cout << a << endl;//8
}

地址传递:形参的改变可以改变实参的值

void fun(int* x) {
	(*x)++;//不加括号就会先自增再解引用
}
int main() {
	int a = 8;
	fun(&a);
	cout << a << endl;//9
}

引用传递:形参的改变可以改变实参的值

void fun(int& x) {
	x++;
}
int main() {
	int a = 8;
	fun(a);
	cout << a << endl;//9
}

是不是比使用指针更简洁些呢

那么,可不可以给引用取别名呢?答案是可以的

int a = 8;
int& a1 = a;
int& a2 = a1;//给引用取别名(引用的嵌套)
int& a3 = a;//同一个对象或变量可以取多个别名

引用和指针的区别

  • 指针是另一个变量,而引用是自己本身,指针会占用额外存储空间,但引用不会占用额外存储空间,也就是说别名和真名是同一个东西,共享同一块内存。
  • 指针可以不用初始化赋值,但是引用必须初始化赋值
  • 指针可以有多级指针,但是引用没有多级引用
  • 指针可以改变指向,但是引用不能改变其所指代的变量或对象
  • 指针是间接访问,引用是直接访问

另外,可以将引用的地址赋值给一个指针,此时指针指向的是原来的变量。

引用作为函数参数、使用引用返回函数值

#include <iostream>
using namespace std;

void swap(int &a, int &b)
{
	int t = a;
	a = b;
	b = t;
}

int a[] = {1, 3, 5, 7, 9};

int& index(int i)
{
	return a[i];
}

int main() 
{
	int a = 5, b = 10;
	//交换数字a和b
	swap(a, b);
	cout << "a = " << a << " b = " << b << endl;
	cout << index(2) << endl;   //等价于输出元素a[2]的值
	index(2) = 100;             //等价于将a[2]的值赋为100;
	cout << index(2) << endl;
	
	return 0;
}

关于指针的更多内容:【C语言】指针

C++的一些标准(兼容旧标准)

1.以初始化列表的方式赋值

int c{2};
int d{(int)3.3};
int arr1[6]{1,2,3};

2.空指针

int *p=NULL;//旧标准
int *p1=nullptr;//新标准

3.自动类型

auto x=10.6;//根据初始化赋值的类型决定变量的类型

4.decltype的使用:可以理解为 复制类型

int n=123;
decltype(n) m=100;//定义一个和变量n一样类型的变量m
decltype((n)) k=n;//给变量n取一个别名k,类似于引用 int& k=n;
123

5.给数据类型取别名

typedef int HP;//旧
using MP = int;//新
typedef void(*pFun)();//旧
using PFun = void(*)();//新
typedef char str[10];//旧
using Str = char[10];//新
123456

6.新的for循环语法规则

#include<iostream>
int main() {
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,0 };
	for (int i = 0; i < 10; i++) {
		std::cout << arr2[i] << '\t';
	}
	std::cout<<std::endl;
	//新
	for (auto i : arr2) {
		std::cout << i << '\t';
	}
}

这个方法只能用来遍历数组或者容器,i所代表的是里面存储的数据元素。指针不能这样遍历。


好啦,下面我们就进入C++的系统学习吧!(笔者会陆续更新哦)

三大特点:

①封装——类和对象

②继承与派生

③多态性与虚函数

运算符重载

函数模版与类模版

C++的输入和输出

异常处理和命名空间

STL标准模板库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Fakelocation Server服务器/专业版 ubuntu

前言:需要Ubuntu系统 Fakelocation开源文件系统需求 Ubuntu | Fakelocation | 任务一 任务一 更新Ubuntu&#xff08;安装下载不再赘述&#xff09; sudo -i # 提权 sudo apt update # 更新软件包列表 sudo apt upgrade # 升级已安装的软…

探索Python的HTTP之旅:揭秘Requests库的神秘面纱

文章目录 **探索Python的HTTP之旅&#xff1a;揭秘Requests库的神秘面纱**第一部分&#xff1a;背景介绍第二部分&#xff1a;Requests库是什么&#xff1f;第三部分&#xff1a;如何安装Requests库&#xff1f;第四部分&#xff1a;Requests库的五个简单函数使用方法第五部分&…

WPF——ICON按钮制作

前言 首先ICON按钮&#xff0c;即带图标按钮&#xff0c;即图标按钮。 图标按钮在开发时&#xff0c;主要是有两种方式来进行。一是在Button的Content内添加Image&#xff0c;然后设置Image的属性Source来实现&#xff0c;这种方式主要是简单易操作&#xff0c;对于初学者来说…

【MySQL篇】持久化和非持久化统计信息的深度剖析(第一篇,总共六篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

三开关VUE组件

一、使用效果 <template><QqThreeSwitch v-model"value" /><!-- <SqThreeSwitch v-model"value" :options"[test1, test2, test3]"><template #left-action><div style"display: flex"><IconMoon…

线段树与树状数组 (C++)

线段树&#xff1a;基于分治思想的二叉树&#xff0c;用于维护区间信息&#xff08;区间和&#xff0c;区间最值等&#xff09;&#xff0c;区间修改和区间查询的时间复杂度为logn 叶子节点存储元素本身&#xff0c;非叶子节点存取区间信息 1.节点&#xff1a;是一个结构体&a…

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数 微信公众平台添加配置 微信公众平台 > 开发管理 > 开发设置 > 扫普通链接二维码打开小程序 配置链接规则需要下载校验文档给后端存入服务器中&#xff0c;保存配置的时候会校验一次&#xff0c;确定当前的配…

数据结构(初阶6)---二叉树(遍历——递归的艺术)(详解)

二叉树的遍历与练习 一.二叉树的基本遍历形式1.前序遍历(深度优先遍历)2.中序遍历(深度优先遍历)3.后序遍历(深度优先遍历)4.层序遍历&#xff01;&#xff01;(广度优先遍历) 二.二叉树的leetcode小练习1.判断平衡二叉树1&#xff09;正常解法2&#xff09;优化解法 2.对称二叉…

spring boot2.7集成OpenFeign 3.1.7

1.Feign Feign是一个声明式web服务客户端。它使编写web服务客户端更容易。要使用Feign&#xff0c;请创建一个接口并对其进行注释。它具有可插入注释支持&#xff0c;包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持&…

基于Redis内核的热key统计实现方案|得物技术

一、Redis热key介绍 Redis热key问题是指单位时间内&#xff0c;某个特定key的访问量特别高&#xff0c;占用大量的CPU资源&#xff0c;影响其他请求并导致整体性能降低。而且&#xff0c;如果访问热key的命令是时间复杂度较高的命令&#xff0c;会使得CPU消耗变得更加严重&…

CTF-Hub SQL 报错注入(纯手动注入)

​ 当输入1时&#xff0c;发现只有查询正确&#xff0c;基本上可以判断出没有回显 开始注入(工具hackerBar) 题目是报错注入&#xff0c;方向就比较明显&#xff0c;大致说一下用到的函数和原理。 常见报错注入函数&#xff1a; 通过 floor() 报错注入通过 extractValue() …

Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?

大家好&#xff0c;我是锋哥。今天分享关于【Elasticsearch中的节点&#xff08;比如共20个&#xff09;&#xff0c;其中的10个选了一个master&#xff0c;另外10个选了另一个master&#xff0c;怎么办&#xff1f;】面试题。希望对大家有帮助&#xff1b; Elasticsearch中的节…

linux安装mysql8.0.40

一、下载MySQL安装包 1.查看glibc版本 rpm -qa | grep glibc 2.到mysql官网下载安装包 ​ 二、解压安装 1.上传压缩包纸/usr/local 目录下&#xff0c;解压&#xff1a; tar -xvf mysql-8.0.40-linux-glibc2.17-x86_64.tar.xz 2.重命名&#xff1a; mv mysql-8.0.40-linux-…

【大数据学习 | Spark-Core】RDD的五大特性(包含宽窄依赖)

分析一下rdd的特性和执行流程 A list of partitions 存在一系列的分区列表A function for computing each split 每个rdd上面都存在compute方法进行计算A list of dependencies on other RDDs 每个rdd上面都存在一系列的依赖关系Optionally, a Partitioner for key-value RDDs…

在 Taro 中实现系统主题适配:亮/暗模式

目录 背景实现方案方案一&#xff1a;CSS 变量 prefers-color-scheme 媒体查询什么是 prefers-color-scheme&#xff1f;代码示例 方案二&#xff1a;通过 JavaScript 监听系统主题切换 背景 用Taro开发的微信小程序&#xff0c;需求是页面的UI主题想要跟随手机系统的主题适配…

【C语言】int *p[ ] 与 int (*p)[ ] 的区分辨析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;基本概念&#xff1a;数组与指针&#x1f4af;理解 int *p[10] 与 int (*p)[10]1. int *p[10]&#xff1a;存放指针的数组2. int (*p)[10]&#xff1a;指向数组的指针 …

Vue3 el-table 默认选中 传入的数组

一、效果&#xff1a; 二、官网是VUE2 现更改为Vue3写法 <template><el-table:data"tableData"border striperow-key"id"ref"tableRef":cell-style"{ text-align: center }":header-cell-style"{background: #b7babd…

MT6769/MTK6769核心板规格参数_联发科安卓主板开发板方案

MT6769安卓核心板具有集成的蓝牙、FM、WLAN和GPS模块&#xff0c;是一个高度集成的基带平台&#xff0c;结合了调制解调器和应用处理子系统&#xff0c;以支持LTE/LTE-A和C2K智能手机应用。 该芯片集成了两个工作频率高达2.0GHz的ARMCortex-A75内核、六个工作频率高达1.70GHz的…

在Excel中处理不规范的日期格式数据并判断格式是否正确

有一个Excel表&#xff0c;录入的日期格式很混乱&#xff0c;有些看着差不多&#xff0c;但实际多一个空格少一个字符很难发现&#xff0c;希望的理想格式是 1980-01-01&#xff0c;10位&#xff0c;即&#xff1a;“YYYY-mm-dd”&#xff0c;实际上数据表中这样的格式都有 19…

flask请求头回显的学习和探究如何进行错误页面污染回显

请求头 首先我们要了解一些flask的请求和响应是利用了什么。 flask的请求和响应主要利用了werkzeug&#xff0c;那么我们就要先了解一下什么是werkzeug&#xff0c;其结构又是什么。 werkzeug是一个基于python开发的一个web工具包&#xff0c;其是flask的核心组件之一。其功能…