博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C扩展 C++回顾到入门
阅读量:5217 次
发布时间:2019-06-14

本文共 9137 字,大约阅读时间需要 30 分钟。

引言

  C扩展也称C++, 是一个复(za)杂(ji)优(ken)秀(die)的语言. 本文通过开发中常用C++方式

来了解和回顾C++这么语言. C++看了较多的书但还是觉得什么都不会. 只能说自己还付出太少,哎.

在引言部分我们先感受C++类的设计.

有个如下需求, 设计一个简单的日志系统. 先看下面 LogSimple.hpp

#ifndef _HPP_LOGSIMPLE#define _HPP_LOGSIMPLE#include 
using namespace std;// 特殊技巧构建类构造器class LogInit { // 设置LogSimple为友员, 可以访问当前私有属性 friend class LogSimple; // _log写普通文件, _wf写级别高的文件 static FILE* _log; static FILE* _wf; // 私有的构造器, 证明这个类是私有类 LogInit() { const char* log = "rpc.log"; const char* wf = "rpc.log.wf"; _log = fopen(log, "ab"); if (NULL == _log) { fprintf(stderr, "fopen is error : %s\n", log); exit(EXIT_FAILURE); } _wf = fopen(wf, "ab"); if (NULL == _wf) { fclose(_log); fprintf(stderr, "fopen is error : %s\n", wf); exit(EXIT_FAILURE); } } // 析构打开的句柄 ~LogInit() { fclose(_wf); fclose(_log); }};// 定义静态变量FILE* LogInit::_log = NULL;FILE* LogInit::_wf = NULL;// 基础的日志系统class LogSimple {protected: // 只能在当前类和继承类中使用的单例对象, 这个只是声明 static LogInit _li;protected: // 打印普通信息 void LogWrite(string msg) { fprintf(LogSimple::_li._log, msg.c_str()); } // 打印等级高信息 void WfWrite(string msg) { fprintf(LogSimple::_li._wf, msg.c_str()); }public: virtual void Log(string msg) = 0;};// 定义在 LogSimple 中声明的静态量LogInit LogSimple::_li;// Debug 模式日志class LogDebug : public LogSimple {public: // 重写Log输出内容 void Log(string msg) {#if defined(_DEBUG) this->LogWrite(msg);#endif }};// Debug 模式日志class LogFatal : public LogSimple {public: // 重写Log输出内容 void Log(string msg) { this->LogWrite(msg); this->WfWrite(msg); }};#endif // !_HPP_LOGSIMPLE

这里使用了 *.hpp 文件,也称C++的充血模型. 当使用 hpp头文件时候表示当前代码是开源的, 头文件和实现都在一起.

并且不使用全局变量和全局函数.

还有这段代码

// 设置LogSimple为友员, 可以访问当前私有属性    friend class LogSimple;......        // 只能在当前类和继承类中使用的单例对象, 这个只是声明    static LogInit _li;

是构建上层语言的 类的构造器. "只会在第一次使用这个类的时候构建这个对象". C++中通过技巧能够完成一切, 是一个强调技巧,强混乱约束的语言.

测试代码如下 main.cpp

#include "LogSimple.hpp"/* * 主函数, 测试简单的日志系统 * 快速熟悉C++类的使用方法. */int main(void) {    LogSimple *log;    LogDebug debug;    LogFatal fatal;    // 简单测试    log = &debug;    log->Log("debug 日志测试!\n");    log = &fatal;    log->Log("fatal 日志测试\n");    // 测试完毕    puts("测试完毕!");    system("pause");    return 0;}

运行结果

生成日志文件图

 

再扯一点, C++类中静态变量, 分两步构造,先在类中声明, 再在外面定义分配实际空间. 好,这里关于C++的类回顾完毕. 

 

前言

  前言部分回顾一下C++中模板用法.

开始先回顾了解函数模板, 看下面测试文件 main.cpp

#include 
using namespace std;/* * 快速排序递归核心, 当前是从小到大排序 */template
static void_sortquick(T a[], int si, int ei) { // 递归结束条件 if (si >= ei) return; int low = si, high = ei; T axle = a[low]; while (low < high) { // 找最右边不合适点 while (low < high && a[high] > axle) --high; if (low >= high) break; a[low++] = a[high]; //找最左边不合适点 while (low < high && a[low] < axle) ++low; if (low >= high) break; a[high--] = a[low]; } // 分界点找好了, 归位 此时low == high a[low] = axle; //新一轮递归 _sortquick(a, si, low - 1); _sortquick(a, high + 1, ei);}// 包装对外使用的快排接口template
inline void sortquick(T a[], int len) { _sortquick(a, 0, len - 1);}/* * 这里温故函数模板,以快速排序为例 */int main(void) { // 开始测试, 模板函数 int a[] = {
5, 6, 1, 2, 4, 5, 1, 4, 14, 1, 17 }; // 开始调用测试 是 sortquick
自动推导 sortquick(a, sizeof(a) / sizeof(*a)); puts("排序后数据为:"); for (int i = 0; i < sizeof(a) / sizeof(*a); ++i) printf("%d ", a[i]); putchar('\n'); system("pause"); return 0;}

通过 template<typename T> 构建一个模板的快排函数. 测试结果如下

 再来回顾一下 模板类用法 我们构建一个 简单的 智能指针类 AutoPtr.hpp

#ifndef _HPP_AUTOPTR#define _HPP_AUTOPTR#include 
#include
/** *简单的智能指针,支持创建基本类型 基本类型数组 *支持智能管理对象类型,对象数组类型 *不允许赋值构造,复制构造,不允许new创建 */template
class AutoPtr { T *_ptr; unsigned _len; AutoPtr
(const AutoPtr
&autoPtr); AutoPtr
&operator=(const AutoPtr
&autoPtr); void *operator new(unsigned s);public: AutoPtr(unsigned len = 1U) { this->_len = len; this->_ptr = !len ? NULL : (T*)calloc(len, sizeof(T)); } ~AutoPtr(void) { for (unsigned u = this->_len; u > 0U; --u) this->_ptr[u - 1].~T();//delete的本质 free(this->_ptr); } inline T& operator*(void) const { return *this->_ptr; } inline T* operator->(void) const { return this->_ptr; } inline T& operator[](unsigned idx) const { return this->_ptr[idx]; } inline T* operator+(unsigned idx) const { return this->_ptr + idx; } //获取智能托管资源的长度,在数组中有用 inline unsigned size(void) { return this->_len; }};#endif // !_HPP_AUTOPTR

测试代码如下 main.cpp

#include 
#include "AutoPtr.hpp"using namespace std;struct abx { int a; float b; char *c;};/* * 这里将处理 泛型类的使用讲解 * 泛型还是在开发中少用.这里只是初级熟悉篇. */int main(void) { // 先使用基础的用法 AutoPtr
iptr; *iptr = 666; printf("*iptr = %d\n", *iptr); // 使用 数组类型 AutoPtr
abs(10); printf("abs[6].c = %s\n", abs[6].c); system("pause"); return 0;}

演示结果

通过上面两个例子, 练习一下基本熟悉泛型语法简易用法了.高级的用法, 那还得春夏秋冬......

 

正文

  这里简单讲解STL中开发中用到的容器类.使用一些简单例子,方便上手使用.

先看list 链表使用案子

同样通过代码开始 main.cpp, 通过list处理随机业务.

#include 
#include
#include
#include
using namespace std;/* * 主函数 - 熟悉STL list 用法 * 业务需求如下: * 有一堆这样数据 * 标识 权重 * 1 100 * 2 200 * 3 100 * ... ... * 需要随机出一个数据. */class RandGoods { list
idxs; //存所有索引的 list
weights; //存所有权重的 int sum; //计算总的权重和public: RandGoods(void) { this->sum = 0; // 初始化随机种子 srand((unsigned)time(NULL)); } /* * 添加数据 */ void Add(int idx, int weidth) { // 简单检测一下参数 assert(idx>=0 && weidth > 0); this->idxs.push_front(idx); this->weights.push_front(weidth); this->sum += weidth; } // 得到一个随机数据 int Get(void) { int ns = 0; int rd = rand() % sum; int len = this->weights.size(); list
::iterator it = this->idxs.begin(); list
::iterator wt = this->weights.begin(); while (wt != this->weights.end()) { ns += *wt; if (ns > rd) return *it; ++it; ++wt; } return -1; } // 输出所有数据 void Print(void) { list
::iterator it = this->idxs.begin(); list
::iterator wt = this->weights.begin(); puts("当前测试数据如下:"); while (wt != this->weights.end()) { printf("%3d %3d\n", *it, *wt); ++it; ++wt; } }};/* * 温故 list用法, C++ STL 没有上层语言封装的好用 */int main(void) { // 随机对象 RandGoods rg; int len = rand() % 20 + 5; // 返回是 [5, 24] //添加数据 for (int i = 0; i < len; ++i) { int weight = rand() % 200 + 1; rg.Add(i, weight); } // 这里测试 得到数据 rg.Print(); // 得到一个数据 int idx = rg.Get(); printf("得到随机物品索引:%d\n", idx); system("pause"); return 0;}

对于STL 库有很多功能, 这里就是最简单的使用方式. 工作中需要用到高级的用法, 可以及时查. 关键是有思路.

演示结果

C++ 的list 没有 java和C#的List好用. 差距太大. 或者说STL相比上层语言提供的容器, 显得不那么自然. 估计是C++是开创者,

后面的语言知道坑在那, 简化创新了. 也可以用vector可变数组代替list. 如果在C中直接用语法层提供的可变数组 int max = 10; int a[max];

在栈上声明可变数组就可以了.

 

再看queue 队列使用方式

关于stl 容器用法都是比较基础例子, 重点能用, 高级的需要看专门介绍的书籍. 关于队列底层库中常用. 和多线程一起配合.

流程很绕, 这里简单写个容易的例子如下main.cpp

#include 
#include
using namespace std;/* * 这里使用 queue队列, 简单使用了解 * 最简单的生产后, 直接消耗 */int main(void) { queue
qds; int i, len = rand() % 20 + 5; double c; int a, b; puts("生产的数据如下:"); // 先生产 队列是尾巴插, 头出来 for (i = 0; i < len; ++i) { a = rand(); b = rand(); if (a >= b) c = a + 1.0 * b / a; else c = (double)-b - 1.0 * a / b; // 队列中添加数据 printf("%f ", c); qds.push(c); } puts("\n释放的数据如下:"); while (!qds.empty()) { c = qds.front(); printf("%f ", c); qds.pop(); } putchar('\n'); system("pause"); return 0;}

运行截图如下

注意的是C++队列是尾查头出.

 

后看map 键值对使用例子

先看 main.cpp

#include 
#include
#include
using namespace std;/* * 这里是使用 map. 简单的熟悉map的使用方法 */int main(void) { map
kvs; const char* strs[] = { "Sweet", "are", "the", "uses", "of", "adversity", "Knowledge", "is", "one", "thing", "but", "faith", "is", "another" }; // 先添加数据 int i; pair
::iterator, bool> pit; for (i = 1; i < sizeof(strs) / sizeof(*strs); ++i) { pit = kvs.insert(pair
(strs[i - 1], strs[i])); if (!pit.second) { printf("插入失败<%s,%s>\n", strs[i-1], strs[i]); } } // 这里开始查找处理 map
::iterator it = kvs.find("are"); if (it != kvs.end()) printf("找见了 %s => %s\n", it->first.c_str(), it->second.c_str()); else printf("没有找见 are => NULL\n"); // 全局输出 puts("当前的数据内容如下:"); for (it = kvs.begin(); it != kvs.end(); ++it) { printf("%s => %s\n", it->first.c_str(), it->second.c_str()); } system("pause"); return 0;}

运行结果

到这里基本上C++ 语言中常用的语法规则, 基本都回顾熟悉完毕了. 后面随着开发, 慢慢了解突破. 最快的熟悉手段还是大量看专业书籍和敲代码. 

 

后记

  错误是难免, 这里纯属回顾C++基础语法. 有问题随时交流, 接受任何C++高玩的批评. 拜~~

 

转载于:https://www.cnblogs.com/life2refuel/p/5430930.html

你可能感兴趣的文章
JavaScript中的Map
查看>>
cat 生成文件 运行脚本
查看>>
didReceiveMemoryWarning-内存警告处理方法-iOS
查看>>
设计模式(一)
查看>>
神奇的口袋(dp)
查看>>
怎样使U盘可以COPY超过4G的文件
查看>>
重构第一天:封装集合
查看>>
Gitlab 维护措施
查看>>
Linux下介绍一款不错的HTML编辑器
查看>>
尚学堂--Java异常
查看>>
Django Rest Framework --序列化、请求数据校验
查看>>
Spring的常用工具类
查看>>
本地-云端的文件传输
查看>>
在Gridview编辑时添加DropDownList控件并设置默认值
查看>>
hdu 1596 find the safest road
查看>>
codeforces 598D Igor In the Museum
查看>>
核心②undefined 和 null
查看>>
Android--UI之ProgressBar
查看>>
DOS操作数据库基础
查看>>
Windows 8 商店应用开发设计十大常见问题(一)
查看>>