C++新手入门指南:从基础概念到实践之路

C++ 继承了 C 语言的高效性和灵活性,同时新增了面向对象编程的特点。这使得 C++ 既可以进行底层系统编程,又能进行面向对象的软件设计。在面向对象编程方面,C++ 支持封装、继承和多态三大特性。 


💯C++ 初印象 

语言的发展就像是练功打怪升级一样,也是逐步递进,由浅入深的过程。我们先来看下C++的历史版本。 

😏C++的发展史: 

C++还在不断的向后发展。但是:⭐现在公司主流使用还是C++98C++11,所有大家不用追求最新,重点将C++98和C++11掌握好,等工作后,随着对C++理解不断加深,有时间可以去琢磨下更新的特性。

 


💯关键概念深入探索

(一)命名空间

命名空间是 C++ 中用于避免命名冲突和组织代码的重要机制。它可以将变量、函数、类等标识符包含在一个逻辑空间中,避免与其他代码中的标识符发生冲突

🌷如图:

😏我们加入命名空间就能解决这个问题: 

定义和使用方法

可以使用namespace关键字来定义命名空间。例如:

namespace MyNamespace {

    int myVariable = 10;

    void MyFunction() 
        {

            std::cout << "Hello from MyNamespace!" << std::endl;

        }

}

要使用命名空间中的成员,可以使用作用域解析运算符 :: 来指定命名空间。例如:MyNamespace::MyFunction();。也可以使用using namespace关键字将命名空间中的标识符导入到当前代码中,以便更方便地使用。例如:using namespace MyNamespace;,之后就可以直接使用命名空间中的标识符,如MyFunction();。

引入命名空间成员的方式

  • 使用作用域解析运算符::对命名空间成员进行限定,如MyNamespace::myVariable。
  • 使用using命名空间成员名,如using MyNamespace::myFunction;,之后可以直接使用myFunction而无需再输入命名空间前缀。
  • 使用using namespace命名空间名,如using namespace MyNamespace;,声明了在本作用域中要用到命名空间MyNamespace中的成员,在使用该命名空间的任何成员时都不必再使用命名空间限定。


(二)输入输出

#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}

C++ 与 C 语言的输入输出方式有很大不同。在 C 语言中,通常使用scanf和printf进行输入输出操作,需要给出格式控制字符串,并且记忆繁多的占位符。而 C++ 使用iostream头文件中的cin和cout进行输入输出,更加方便易用。

cin是标准输入流,通常与流提取运算符>>结合使用。C++ 编译器会根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。例如:int a, b; cin >> a >> b;。

cout是标准输出流,通常与流插入运算符<<结合使用。C++ 编译器会根据要输出变量的数据类型,选择合适的流插入运算符来显示值。例如:cout << "Hello, World!" << endl;。

endl表示换行,与 C 语言中的\n作用相同,它是 “end of line” 的缩写。


(三)缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值🌟在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参

分类

  • 全缺省参数:给所有参数都指定一个默认值。例如:void TestFunc(int a = 10, int b = 20, int c = 30)。
  • 半缺省参数:给部分参数指定一个默认值。例如:void TestFunc(int a, int b = 20, int c = 30)。

 

❗​​​​​​​注意事项:

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给。
  2. 缺省参数不能在函数声明和定义中同时出现。
  3. 缺省值必须是常量或者全局变量。
  4. C 语言不支持缺省参数。


(四)函数重载

函数重载是 C++ 的一种特殊情况,允许在同一作用域中声明几个功能类似的同名函数,只要它们的参数列表不同就可以。参数列表不同包括参数的个数不同、类型不同或顺序不同。

例如:

int Add(int left, int right) {

cout << "int Add(int left, int right)" << endl;

return left + right;

}

double Add(double left, double right) {

cout << " double Add(double left,double right)" << endl;

return left + right;

}

这里有两个同名函数Add,但参数类型不同,一个是int类型,一个是double类型。

👀C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同👇 

#include<iostream>
using namespace std;

// 1、参数类型不同
int Add(int left, int right)
{
    cout << "int Add(int left, int right)" << endl;
    return left + right;
}
double Add(double left, double right)
{
    cout << "double Add(double left, double right)" << endl;
    return left + right;
}

// 2、参数个数不同
void f()
{
    cout << "f()" << endl;
}
void f(int a)
{
    cout << "f(int a)" << endl;
}

// 3、参数类型顺序不同
void f(int a, char b)
{
    cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
    cout << "f(char b, int a)" << endl;
}
int main()
{
    Add(10, 20);
    Add(10.1, 20.2);
    f();
    f(10);
    f(10, 'a');
    f('a', 10);
    return 0;
}

返回值类型不同不能作为重载函数原因是,在调用函数时,编译器是通过参数列表来确定调用哪个函数,而不是返回值类型。如果仅靠返回值类型不同来重载函数,编译器无法确定应该调用哪个函数。


(五)引用

1.引用的概念​​​​​​​

引用就如同给已存在的变量取了一个别名。👻比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。,这里的李逵就相当于一个已存在的变量,“铁牛” 和 “黑旋风” 就是对李逵的引用。在编程中,引用变量和它所引用的原始变量共用同一块内存空间,这意味着对引用变量的操作实际上就是对原始变量的操作。

2.引用的特点

  1. 引用在定义时必须初始化

    • 这就好比你不能只说有一个别名,但不指出这个别名对应哪个具体的人。在编程中,如果不初始化引用,就不知道这个引用指向哪个具体的变量,会导致编译错误。
    • 例如:int a = 10; int& b; // 错误,引用 b 未初始化。正确的做法是:int a = 10; int& b = a; // 正确,引用 b 初始化为变量 a
  2. 一个变量可以有多个引用

    • 继续以李逵的例子来说,李逵除了 “铁牛” 和 “黑旋风” 这两个别名外,可能还有其他的称呼。在编程中,一个变量可以被多个引用指向,每个引用都代表这个变量的不同别名。
    • 例如:int a = 10; int& b = a; int& c = a; // 变量 a 有两个引用 b 和 c
  3. 引用一旦引用一个实体,再不能引用其他实体

    • 就像李逵被称为 “铁牛” 后,这个 “铁牛” 的别名就不能再用来称呼其他人了。在编程中,一旦引用被初始化为某个变量,它就不能再指向其他变量。
    • 例如:int a = 10; int b = 20; int& c = a; c = b; // 这里是将变量 b 的值赋给引用 c 所指向的变量 a,而不是让引用 c 指向变量 b

3.常引用的应用
void TestConstRef()
{
  const int a = 10;
  /*int& ra = a;  该语句编译时会出错,普通引用(int&)不能绑定到常量上,
因为普通引用是可修改的,它可以通过引用改变所绑定的变量的值。
而常量不能被修改,所以会出现编译错误。*/
  const int& ra = a;
  /* int& b = 10; 该语句编译时会出错,10是一个常量值,不是一个变量。
普通引用必须绑定到一个变量上,不能绑定到常量值,所以会编译错误。*/
  const int& b = 10;
  double d = 12.34;
  /*int& rd = d;该语句编译时会出错,d是一个double类型的变量,
而普通引用(int&)要求所绑定的对象类型必须完全一致。这里类型不匹配,所以会出现编译错误。*/
  const int& rd = d;
}

 常引用可以引用普通变量、常量或字面常量。例如:const int& ra = a;。

4.引用做参数和返回值的场景
  • 做参数:可以避免值传递时的拷贝开销,提高效率。例如:void swap(int& a, int& b)。
    void Swap(int& left, int& right)
    {
     int temp = left;
     left = right;
     right = temp;
    }
  • 做返回值:可以返回一个变量的引用,实现链式操作。 
    int& Count()
    {
     static int n = 0;
     n++;
     // ...
     return n;
    }

5.引用与指针的区别
  1. 不存在空引用,引用必须连接到一块合法的内存;而指针可以为空。
  2. 一旦引用被初始化为一个对象,就不能被指向到另一个对象;指针可以在任何时候指向到另一个对象。
  3. 引用必须在创建时被初始化;指针可以在任何时间被初始化。
  4. 引用在 sizeof 中结果为引用类型的大小;指针在 sizeof 中是地址空间所占字节个数(32 位平台下占 4 个字节)。
  5. 有多级指针,但没有多级引用。
  6. 引用比指针更安全,访问实体的方式不同,指针需要显式解引用,引用编译器自己处理。


(六)内联函数

内联函数是一种在编译时将函数体插入到调用处的函数,以减少函数调用的开销。

🔥​​​​​​​以下是用 C++ 代码解释内联函数:

#include <iostream>

// 普通函数
int addNormal(int a, int b) {
    return a + b;
}

// 内联函数
inline int addInline(int a, int b) {
    return a + b;
}

int main() {
    int x = 5, y = 10;

    // 调用普通函数
    int resultNormal = addNormal(x, y);
    std::cout << "Result using normal function: " << resultNormal << std::endl;

    // 调用内联函数
    int resultInline = addInline(x, y);
    std::cout << "Result using inline function: " << resultInline << std::endl;

    return 0;
}

在上述代码中,定义了两个函数addNormaladdInline,分别作为普通函数和内联函数实现两个整数相加的功能。在main函数中分别调用这两个函数,可以看到内联函数在编译时会将函数体直接插入到调用处,避免了函数调用的开销

需要注意的是,编译器并不一定会将addInline函数真正内联处理,它会根据具体情况进行优化决策。如果函数体比较复杂或者有其他不适合内联的情况,编译器可能会选择不进行内联。


(七)auto 关键字(C++11)

在 C++11 中,auto关键字用于自动类型推导它可以根据初始化表达式的类型自动推断出变量的类型。

👉例如:auto i = 10;,这里i的类型会被自动推导为int

auto不能推导的情况包括:

  1. 函数参数的类型不能用auto推导。
  2. 数组的类型不能用auto推导,但是可以用auto推导数组的元素类型,然后结合std::begin和std::end来遍历数组。

🔥代码解释: 

#include <iostream>
#include <vector>
#include <algorithm>

// 正常使用 auto 进行类型推导
void normalAutoUsage() {
    auto i = 10;
    std::cout << "Type of i is deduced as int. Value of i: " << i << std::endl;

    auto str = "Hello, world!";
    std::cout << "Type of str is deduced as const char*. Value of str: " << str << std::endl;
}

// 函数参数不能用 auto 推导
void cannotDeduceFunctionParams(auto a) {
    // 错误,不能用 auto 推导函数参数类型
}

// 数组的类型不能用 auto 推导,但可以推导元素类型并遍历
void arrayDeduction() {
    int arr[] = {1, 2, 3, 4, 5};
    // auto arr2 = arr; // 错误,不能用 auto 推导数组类型
    for (auto element : arr) {
        std::cout << "Array element: " << element << std::endl;
    }
}

int main() {
    normalAutoUsage();
    // cannotDeduceFunctionParams(10); // 会编译错误
    arrayDeduction();
    return 0;
}


(八)基于范围的 for 循环(C++11)

在 C++11 中,基于范围的 for 循环提供了一种更简洁的方式来遍历容器或数组。

传统的 for 循环遍历数组(C++98)

int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
std::cout << "传统 for 循环遍历数组:";
for (int i = 0; i < len; i++) {
    std::cout << arr[i] << " ";
}
std::cout << std::endl;

 基于范围的 for 循环遍历数组(C++11)

int arr[] = {1, 2, 3, 4, 5};
std::cout << "基于范围的 for 循环遍历数组:";
for (int& x : arr) {
    std::cout << x << " ";
}
std::cout << std::endl;

 for (int& x : arr):这是 C++11 中基于范围的 for 循环语法。在这里,arr 是要遍历的数组。int& x 表示定义了一个引用类型的变量 x,它会依次引用数组中的每个元素使用引用的好处是可以在循环体内修改数组元素的值,如果只是读取元素的值,也可以使用 const int& x 或者 int x


(九)指针空值 nullptr

在 C++11 中,引入了nullptr作为指针的空值。与 C++98 中的指针空值(如NULL或 0)相比,nullptr具有更好的类型安全性。

nullptr可以明确表示指针为空,避免了与整数类型的混淆。

👇以下是用 C++ 代码解释 C++11 中的指针空值 nullptr

#include <iostream>

void func(int num) {
    std::cout << "Called function with integer parameter: " << num << std::endl;
}

void func(int* ptr) {
    if (ptr == nullptr) {
        std::cout << "Called function with pointer parameter (nullptr)." << std::endl;
    } else {
        std::cout << "Called function with pointer parameter (non-null): " << *ptr << std::endl;
    }
}

int main() {
    // 使用 nullptr 调用指针参数的函数
    func(nullptr);

    int num = 10;
    // 使用整数地址调用指针参数的函数
    func(&num);

    // 使用 0 调用可能产生歧义
    func(0);

    return 0;
}

在这个例子中:

  • 定义了两个重载的函数 func,一个接受整数参数,另一个接受指针参数。
  • 在 main 函数中,分别使用 nullptr、整数变量的地址和 0 来调用 func 函数。
  • 使用 nullptr 可以明确地表示调用指针参数的函数,并且不会产生歧义。而使用 0 可能会导致调用歧义,因为编译器可能不确定是调用整数参数的函数还是指针参数的函数(在某些情况下,0 可能被视为整数常量,也可能被视为空指针常量)。

通过这个例子可以看出,nullptr 在表示指针空值时具有更好的类型安全性。


💯C++资源推荐

 

1.在线课程

  • C++ 程序设计北京大学:由刘家瑛教授和郭炜教授授课,面向已经掌握 C 语言的学员,将掌握 C++ 语言中的类、对象、运算符重载、继承、多态等面向对象的机制,以及模版、STL 等泛型程序设计的机制。本课程为期 4 周,每周 8 - 10 小时。
  • Fundamentals of C++ IBM 公司:由 Sathya Ponmalar 等授课,将开启你的 C++ 程序员之旅,通过许多自动评估的 C++ 编码活动,帮助你理解 C++ 的语法和语义,并建立强大的编程和解决问题的技能。本课程为期 5 周,每周 5 - 6 小时。
  • C++ 程序设计西北工业大学:由魏英教授授课,使学员能够使用一种开发工具熟练的进行软件开发,为学员将来的创新实验、毕业设计、科学研究提供有力的技术支持。本课程为期 20 周,每周 6 小时。
  • C++ Programming: Basic Skills Codio 公司:由 Anh Le 授课,教你用 C++ 写一个简单程序所需的基本技能。课程是为没有编码经验的学习者设计的,本课程为期 5 周,每周 2 - 3 小时。
  • Introduction to C++ 微软公司:由 Gerry O'Brien 等授课,介绍 C++ 语言,课程由四个模块组成:C++ 语法、C++ 语言基础、如何在 C++ 中创建函数、为微软公司后续中级和高级 C++ 课程做好准备。本课程为期 4 周,每周 3 - 5 个小时。
  • Object-Oriented Data Structures in C++ 伊利诺伊大学香槟分校:由 Wade Fagen-Ulmschneider 教授授课,将教你如何用 C++ 语言编写程序,包括如何建立一个编写和调试 C++ 代码的开发环境,以及如何将数据结构实现为 C++ 分类。本课程为期 4 周,每周 3 - 7 个小时。

2.官方文档:C++ 的官方文档提供了最准确、最全面的语言规范和指南,是学习与参考的宝贵资源。

3.社区论坛

c++ 博客(A Charmer)

Stack Overflow:解决编程问题的知名社区,在 C++ 编程方面有大量的问题和解答。

Reddit:参与 C++ 社区讨论,获取最新的 C++ 资讯和学习资源。


以上就是本文的全部内容了!

📣​​​​​​​​​​​​如果你想深入了解 C++,欢迎持续关注我【A Charmer】​​​​​​​,我将为你带来更多精彩的编程知识分享。😉

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】Docker基本操作

目录 一、了解云计算背景 1.1 云计算的三种服务模式 1.2 虚拟机的两种架构 二、Docker 概述 2.1 Docker简述 2.2 Docker 特点 2.3 Docker与虚拟机的区别 2.4 容器技术有哪些 2.4.1 namespace的六项隔离 2.5 Docker核心概念 2.5.1 镜像 2.5.2 容器 2.5.3 仓库 三、…

吴恩达深度学习笔记(6)

正交化 为了提高算法准确率&#xff0c;我们想到的方法 收集更多的训练数据增强样本多样性使用梯度下降将算法使算法训练时间更长换一种优化算法更复杂或者更简单的神经网络利用dropout 或者L2正则化改变网络框架更换激活函数改变隐藏单元个数 为了使有监督机制的学习系统良…

笔试强训10.17

//法一&#xff1a;中点扩散 //法二&#xff1a;动态规划 //法三&#xff1a;hash二分 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N1e610; const int base131; ull hr[2*N],hl[2*N],p[2*N];//超过ull自动取余 char s[N*2];…

如何优化批处理策略,最大限度地“压榨”GPU性能

新手数据科学家和机器学习工程师常常会问一个关键问题&#xff1a;如何判断他们的深度学习训练过程是否在正常运行&#xff1f;在本文中&#xff0c;我们将学习如何诊断和优化深度学习的性能问题&#xff0c;不论是在单台机器还是多台机器上进行训练。通过这些方法&#xff0c;…

uniapp onPageScroll

子组件有onPageScroll, 首页也要引入onPageScroll, eg: 主页面 sell/detail/index 《子组件》 <script setup> 引入onPageScroll </script> 组件&#xff1a; 引入onPageScroll 别人的比较

阿里 C++面试,算法题没做出来,,,

我本人是非科班学 C 后端和嵌入式的。在我面试的过程中&#xff0c;竟然得到了阿里​ C 研发工程师的面试机会。因为&#xff0c;阿里主要是用 Java 比较多&#xff0c;C 的岗位比较少​&#xff0c;所以感觉这个机会还是挺难得的。 阿里 C 研发工程师面试考了我一道类似于快速…

五个必备的高清无水印视频素材库推荐

做抖音、短视频创作的朋友都知道&#xff0c;优质的素材往往决定了作品能否获得更多关注。如果你还不知道在哪里下载高清无水印的视频素材&#xff0c;不用担心&#xff01;今天为你推荐5个高品质的视频素材库&#xff0c;助你轻松创作出爆款视频。 蛙学网 是国内领先的视频素材…

Windows 11 24H2版本有哪些新功能_Windows 11 24H2十四大新功能介绍

距离上次发布的23H2版本已经过去了一年时间&#xff0c;现在&#xff0c;Win 11的24H2版本终于等到了&#xff0c;微软已经全面公开发布Win11 24H2版本&#xff0c;版本号为26100.1742&#xff0c;此次官宣的版本包括了消费者版、商业版、LTSC 2024版等&#xff0c;各种语言版本…

选择合适的SSL证书

随着我们在线业务的增长&#xff0c;确保网站安全变得越来越重要。对于许多人来说&#xff0c;保护网站安全的想法似乎令人望而生畏&#xff0c;尤其是在有各种SSL证书可用的情况下。您可能想知道哪一个最适合您的业务需求或如何浏览这些选项。 除了SSL证书之外&#xff0c;使…

IIC协议解析

文章目录 1 IIC理解1.1 IIC简述1.2 IIC协议优缺点1.3 传输速度 2 IIC数据格式3 数据时序3.1 写时序3.2 读时序 参考链接 1 IIC理解 1.1 IIC简述 IIC全称Inter Integrated Circuit&#xff0c;即集成电路总线。是由Philips半导体公司于八十年代初设计出的一种两线式串行总线协议…

雷达手势识别技术

1、IR-UWB 手势识别方案 该任务可以分为数据采集&#xff0c;雷达数据处理&#xff0c;识别分类三个部分。 1.1 UWB Radar 数据处理 首先采集慢时间快时间维数据&#xff1a; 然后仍然是Clutter removal filter&#xff1a; 之后正则化转化为灰度图像&#xff1a; 使用matlab f…

springboot+大数据+基于大数据的电脑硬件推荐系统【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

虚幻闪烁灯光材质

创建一个材质 材质域改成光照函数 , Time让材质动起来 参数B用来控制速度 , Sine 让灯光闪烁 , Frac 增加了闪烁细节 把材质放到灯光材质上 效果还是挺不错的! 可以用于一些恐怖游戏~

Redis和Jedis的区别

目录 含义与用途 Jedis案例 总结 含义与用途 Redis&#xff1a; 概念&#xff1a;Redis是一个基于内存的键值存储数据库&#xff0c;支持丰富的数据结构。比如&#xff1a;字符串功能&#xff1a;除了基础的数据存储&#xff0c;Redis还提供了丰富的高级功能。如持久化&…

Python第七八次作业

1.输入一个大于0的正整数n&#xff0c;如果n 1 ,则返回1&#xff0c; 如果n是偶数&#xff0c;则返回 n // 2 &#xff0c;如果n是奇数&#xff0c;则返回 3n 1&#xff0c;将所有的返回值存放到一个列表中&#xff0c;注意&#xff1a;n是第一个元素&#xff0c;其他的元素根…

entity,pojo,vo,dto 详解

在Java项目中&#xff0c;包名通常用于组织代码&#xff0c;使其更加清晰和易于维护。entity、pojo、vo和dto是常见的包名&#xff0c;它们各自有不同的含义和用途。下面将详细解释这些包名的含义&#xff0c;并提供一个示例&#xff0c;帮助你更好地理解它们在项目中的应用。 …

DAPLINK 之 RTT 输出日志

文章目录 前言1 安装 SEGGER RTT2 OpenOCD 下的 rtt2.1 调试环境2.2 输出日志 3 关于日志中的文件名参考 前言 1&#xff09;RTT&#xff08;Real Time Transfer&#xff0c;实时传输&#xff09;&#xff1a;SEGGER 的 Real Time Transfer (RTT) 是一种经过验证的技术&#x…

mysql查看和修改默认配置

1.查看最大连接数 SELECT max_connections; 或者 SHOW VARIABLES LIKE max_connections;2.查看当前连接的客户端 SHOW PROCESSLIST;2.临时设置最大连接数 SET GLOBAL max_connections 500;3.临时设置连接客户端交互超时时间 SET GLOBAL interactive_timeout 1800;4.永久生…

3.3 Thymeleaf语法

文章目录 引言Thymeleaf标签显示标签链接地址标签条件判断标签元素遍历标签 Thymeleaf表达式变量表达式选择变量表达式消息表达式链接表达式 Thymeleaf内置对象上下文对象上下文变量上下文区域请求对象响应对象会话对象日期对象 实战演练创建控制器创建模板页面 结语 引言 Thy…

【Python爬虫】看电影还在用VIP?一个python代码让你实现电影自由!附源码

今日主题 如何用Python解析vip电影。 什么是vip电影&#xff1f; 这些vip电影啊&#xff0c;想要观看的话&#xff0c;必须充值会员&#xff0c;否则没法看。 比如这个&#xff1a; 这些vip电影解析后呢&#xff1f; 不需要会员&#xff0c;不需要登录&#xff0c;可以直接…