C++鸟瞰(个人心得)

2024-03-13 05:12
文章标签 c++ 个人 心得 鸟瞰

本文主要是介绍C++鸟瞰(个人心得),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

头文件

C++和C一样,在源文件的头部需要加入头文件,来告诉预处理器你需要用到什么库。编写方式也和C语言一样,不过基础头文件不是stdlib.h而是iostream,名字划分为io和stream。

stream翻译过来就是“流”的概念,流的概念不是C++特有的,而是Linux下的一个概念,在Linux下一切皆文件,输入输出也是文件,称为输入流输出流,编程语言输入输出的背后就是用标准输入标准输出来实现的,标准输入流默认绑定在键盘输入,标准输出默认绑定在终端窗口,标准输入输出可以通过重定向绑定到文件或者其他上。

#include<iostream>  //通用的header file使用扩折号
#include"my_self_header_file.h" //自己编写的header文件使用英语双引号

C++在Linux下的默认include查找路径是/usr/local/include和/usr/local/include,当安装了新的库时,要么将该库的include路径加到C_INCLUDE_PATH,要么在默认路径中加一个软链接指向库的include文件夹。我更推荐第二种,便于管理。

命名空间

C++有非常多的开发库,这些库中有很多算法函数名称是一样的,当同时用到两个不同的功能库中一样名称的函数时应该如何区分是来自哪个空间的呢?为了解决这个问题,C++中定义了命名空间这个概念,当出现上面的问题时,可以在函数的前面加上命名空间的名字,就可以区分了。

#include<iosteam>
using namespace std; 
// std 就是基础标准库的命名空间
// using namespace std的意思就是声明我要用到这个命名空间,这样就不需要在变量前加std了
//大型项目最好不要这样直接声明使用整个命名空间,会导致命名空间污染,使用在函数前面加命名空间名称的方式较好。
int main(){cout<<"hello"<<endl;// 如果前面没有声明命名空间,那么就要使用下面这行代码来代替// std::cout<<"hello"<<std::endl;return 0;
}

当我们在参与一个大型项目的时候,我们经常在不同的模块中可能会实现两个名称相同的函数,为了解决这个问题,我们可以进行自定义命名空间,下面代码为如何自定义一个命名空间

#include<iostream>namespace mynamespace{void func(){};
}int main(){mynamespace::func();return 0;
}

命名空间不仅仅对函数有用,也对变量有用。但是有一些常见变量我们可能在一个程序中就会用到很多个同名的,比如temp这个名字,使用频率非常高,难道要都给他们定义一个命名空间吗?C++中的变量声明和函数声明都是有自己的使用空间限制的,出了这个空间声明就无效了,一般都是以{}为一个空间,英文叫一个scope,可以根据大小分为global scope和local scope

其实namespace也是一个scope

#include<iostream>
int globalnum; //这是一个全局变量,就是说在全局通用int main{std::cout<<globalnum<<std::endl;for(int i=0;i<10;i++){std::cout<<globalnum<<std::endl; //可以}std::cout<<i<<std::endl; //会报错,因为已经出了scopereturn 0;
}

面向对象编程

C++是一个较为多元的编程语言,可以满足多种编程范式,C++可以进行面向对象编程。

  • 类class,是抽象的,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象。
  • 对象/实例,是实实在在的,是类的实体化。

面向对象编程比较符合人的直觉,但是想要写出好的面向对象代码不能只靠直觉,面向对象有23种常见的设计模式,是进行面向对象编程所必学的。

#include<iostream>
#include<string>
class Person{
public:Person(const string namestr=0); //构造函数Person(const Person& originalperson);//拷贝函数 构造函数,拷贝函数,析构函数,默认不用写函数返回类型Person& operator= (const Person& originalperson); //拷贝赋值函数inline std::string getName(){return name;}~Person(){};  //析构函数
private:std::string name;int height;int age;
};
inline Person::Person(const std::string namestr)
{if(namestr.size()){name = std::string(namestr);}else{name = std::string();}
}
int main()
{Person bighammer("王大锤");std::cout<<bighammer.getName()<<std::endl;return 0;
}

上面实现了一个最简单的类。麻雀虽小,五脏俱全。一个类最少应该包括以下几部分:

  • 普通构造函数
  • 析构函数
  • 拷贝构造
  • 赋值运算重载

C++中初始化对象可以使用malloc和free,也可以使用new和delete,new和delete会调用类的构造函数和析构函数,可以避免空指针的存在。【二者初始化的对象所在位置也不同,new时在自由存储区为对象动态分配内存,malloc是在堆栈上分配空间】
必须实现拷贝构造的原因是如果不实现拷贝构造,C++会自动为你实现一个完全复制的拷贝构造,如果你的类里面有指针,指针也会被复制过去,这样就可能导致两个对象指向同一个数据,引发bug。

C++标准库 & 模板编程

C++标准库是对C标准库的扩充,对C的库稍作修改,并增加了面向对象以及模板编程的内容。
C++另一种常用编程范式就是模板编程或者说泛型编程,泛型编程的思想是逻辑代码独立于任何特定类型,能够有效实现代码复用。
模板可以分为函数模板和类模板,模板参数又可以分为类型模板参数和非类型模板参数,两两结合,一共四种可能:

template<typename T>  // 类型函数模板
T funcadd(T a, T b)
{T addhe = a + b;return addhe;
}
template<int a, int b>  // 非类型函数模板,浮点数不能作为非类型模板参数
int funcaddv2()
{int addhe = a + b;return addhe;
}
template<typename T> //类型类模板
class MyClass
{
private:T* temp;void func();
}
template<typename T>
void MyClass<T>::func(){}template<int id> // 非类型类模板
class MyClass2
{
private:int number=id;
}
//不过非类型一般都是更类型一块儿用,例如array类
template<typename T,int size>
class Array
{
private:T arr[size];void func2();
}
template<typename T,int size>
void func2(){}

不管是函数模板还是类模板,都是在用到时才能生成一个实例,如果多文件编程,为了防止产生多个实例,可以在类模板的文件中显式实例化:

template MyClass<float> //进行显式实例化
extern template MyClass<float> //其他文件中就只能进行外部实例化声明

这里的实例化是指将模板实例化,生成对应类型的代码,而不是面向对象编程中的将一个类实例化成一个对象。

现代C++中还支持模板特化和偏特化,如果一个模板对于某些特定的类型需要进行单独编写代码,就叫特化,如果所有类型都要进行特殊编写代码,就叫全特化,如果局部类型进行特化,称为偏特化:

template<>
struct TC<int, int>
{TC(){cout << "TC<int,int>特化版本的构造函数" << endl;}// 这里可以对特化的版本做单独的处理
}struct TC<int, double>
{TC(){cout << "TC<int,double>特化版本的构造函数" << endl;}// 这里可以对特化的版本做单独的处理
}template <typename U> // 偏特化,3个参数绑定2个。
struct TCP<int, U, double>
{TCP(){cout << "TCP偏特化版本的构造函数" << endl;}void functest(){cout << "TCP偏特化版本"<< endl;}
}

除此之外,还有模板参数范围特化,可变参数模板,模板模板参数等等,自行了解。

STL标准模板类就是一个模板编程的集大成者,标准模板库STL主要由以下几部分组成:

  • 容器类:数据类型,其中又分为序列容器和非序列容器
  • 算法类:适用于容器类的常见算法的实现,如sort,search
  • 迭代器:适用于容器类的迭代器
  • 适配器:可变容器,迭代器或者函数对象接口的一种组件
  • 函数对象:用类型包装函数
  • 分配器:进行内存分配

现代C++

随着C++的发展,引入了不少新的特性以及编程范式,目前大多将C++11以后的版本,称为现代C++。C++11更新的特性非常多,网上都说C++11是C++跨时代的发展,可以参考:《深入理解C++11:C++11新特性解析与应用》这本书,讲的很好,对于了解C++11很有帮助。

函数式编程

函数编程的思想是:程序是函数定义的表达式树,这些函数将一个值映射到另一个值,而不是传统的状态机模型意义下的命令式语句。
C++11中引入了lambda匿名函数,使得C++进行函数式编程更为容易,函数式编程现在很火,这两年发展迅猛的Rust也是函数式编程的忠实拥护,基本上目前大部分编程语言都支持函数式编程,匿名函数,闭包,是函数式编程中的重要概念。

C++工具 & 功能库

C++因为其标准委员会只负责制定标准,不负责实现,以及C++实现的不统一,导致其工具也非常多。MSVC和GCC和Clang各自都有很多配套的工具,所以学习C++不光要会语法以及特性,还要学习配套的工具和相应领域的工具库,

工具:

Cmake:用于自动化配置编译,生成makefile
ninja:构建系统,也是用于构建cpp项目的
gdb:调试工具
gprof:性能测试工具,来自GNU Binutils,其他的可以不会,这个一定要会用。
valgrind:内存泄漏检测工具

功能库

计算机视觉:OpenCV
矩阵计算:Eigen
客户端开发:Qt
深度学习推理引擎:Onnxruntime

后续想到什么再慢慢缝缝补补吧,C++太大了,太繁杂了,令人眼花缭乱

这篇关于C++鸟瞰(个人心得)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/803732

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

2024/9/8 c++ smart

1.通过自己编写的class来实现unique_ptr指针的功能 #include <iostream> using namespace std; template<class T> class unique_ptr { public:         //无参构造函数         unique_ptr();         //有参构造函数         unique_ptr(