C++的编程思想和进阶编程

简介: ● 一个模式描述了一个不断发生的问题以及这个问题的解决方案;模式是前人的设计经验上总结出来的对于一些普遍存在的问题提供的通用的解决方案;比如单例模式、观察者模式等● 软件中有很多模式面向对象常见的23中设计模式;反模式;企业应用架构模式等

C++的编程思想和进阶编程


软件设计模式

●  一个模式描述了一个不断发生的问题以及这个问题的解决方案;模式是前人的设计经验上总结出来的对于一些普遍存在的问题提供的通用的解决方案;比如单例模式、观察者模式

●  软件中有很多模式
面向对象常见的23中设计模式;
反模式;企业应用架构模式等


泛型编程的思想

●  如果说面向对象是一种通过间接层来调用函数,以换取一种抽象,那么泛型编程则是更直接的抽象,它不会因为间接层而损失效率

●  不同于面向对象的动态期多态(运行时多态),泛型编程是一种静态多态(编译时多态),通过编译器生成最直接的代码

●  泛型编程可以将算法与特定类型、结构剥离,尽可能的复用代码


模板编程的难点很大程度上在于对编译器的理解,我们需要知道怎么帮助编译器提供需要生成代码的信息。


STL

●  STL算法是泛型,不与任何特定数据结构和对象绑定,不必在环境类型的情况下重写代码

●  STL算法可以量身定做,并且有很高的效率

●  STL可以进行扩充,你可以编写自己的组件并且能与STL标准的组件进行很好的配合


六大组件

容器、仿函数、算法、空间配置器、适配器、迭代器


容器

●  容器用于存放数据;STL的容器分为两大类


○  序列式容器


其元素都是可排序的,STL提供了vector/list/deque等序列同期。而stack,queue,priority_queue则是容器适配器


○  关联式容器


每个数据元素都是由一个键(key)和值(value)组成,当元素被插入到容器时,按照其键以某种特定规则放入释放位置;常见的stl关联容器:set map


仿函数

●  仿函数一般不会单独使用,主要是为了搭配STL算法使用

●  函数指针不能满足STL对抽象性的要求,不能满足软件积木的要求,无法和STL其他组件搭配

●  本质就是类重载了一个operator(),创建了一个行为类似于函数的对象

#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <functional>
#include<algorithm>
#include <utility>
#include <iostream>
using namespace std;
struct Display
{
  void operator()(int i)
  {
    cout << i << " ";
  }
};
struct Display2
{
  void operator()(pair<string, double> info)
  {
    cout << info.first << ":  " << info.second << "  ";
  }
};
//struct cmpMap
//{
//  bool operator()(pair<string, double> a, pair<string, double> b)
//  {
//    return a.first.length() < b.first.length();
//  }
//};
int main()
{
  int iArr[] = { 1, 2,3,4,5 };
  vector<int> iVector(iArr, iArr + 4);
  list<int> iList(iArr, iArr + 4);
  deque<int> iDeque(iArr, iArr + 4);
  queue<int> iQueue(iDeque);     // 队列 先进先出
  stack<int> iStack(iDeque);         // 栈 先进后出
  priority_queue<int> iPQueue(iArr, iArr + 4);  // 优先队列,按优先权 
  for_each( iVector.begin(), iVector.end(), Display() );
  cout << endl;
  for_each(iList.begin(), iList.end(), Display());
  cout << endl;
  for_each(iDeque.begin(), iDeque.end(), Display());
  cout << endl;
  while ( !iQueue.empty() )
  {
    cout << iQueue.front() << " ";  // 1  2 3 4
    iQueue.pop();
  }
  cout << endl;
  while (!iStack.empty())
  {
    cout << iStack.top() << " ";    // 4 3  2  1
    iStack.pop();
  }
  cout << endl;
  while (!iPQueue.empty())
  {
    cout << iPQueue.top() << " "; // 4 3 2 1
    iPQueue.pop();
  }
  cout << endl;
    return 0;
}
#include <string>
#include<map>
#include <algorithm>
#include <iostream>
using namespace std;
struct Display
{
  void operator()(pair<string, double> info)
  {
    cout << info.first << ": " << info.second << endl;
  }
};
int main()
{
  map<string, double> studentSocres;
  studentSocres["LiMing"] = 95.0;
  studentSocres["LiHong"] = 98.5;
  studentSocres.insert( pair<string, double>("zhangsan", 100.0) );
  studentSocres.insert(pair<string, double>("Lisi", 98.6));
  studentSocres.insert(pair<string, double>("wangwu", 94.5));
  studentSocres.insert(map<string, double>::value_type("zhaoliu", 95.5) );
  studentSocres["wangwu"] = 88.5;
  for_each(studentSocres.begin(), studentSocres.end(), Display());
  cout << endl;
  map<string, double>::iterator iter;
  iter = studentSocres.find("zhaoliu");
  if (iter != studentSocres.end())
  {
    cout << "Found the score is: " << iter->second << endl;
  }
  else
  {
    cout << "Didn't find the key." << endl;
  }
  // 使用迭代器完成遍历查找的过程
  iter = studentSocres.begin();
  while (iter != studentSocres.end())
  {
    if (iter->second < 98.0)  // 去除不是优秀的同学
    {
      studentSocres.erase(iter++);  // 注意:迭代器失效问题
    }
    else
    {
      iter++;
    }
  }
  for_each(studentSocres.begin(), studentSocres.end(), Display());
  cout << endl;
  for (iter = studentSocres.begin(); iter != studentSocres.end(); iter++)
  {
    if (iter->second <= 98.5)
    {
      iter = studentSocres.erase(iter);  // 注意:迭代器失效问题
    }
  }
  for_each(studentSocres.begin(), studentSocres.end(), Display());
  cout << endl;
  // find得到并删除元素
  //iter = studentSocres.find("LiHong");
  //studentSocres.erase(iter);
  //for_each(studentSocres.begin(), studentSocres.end(), Display());
  //int n = studentSocres.erase("LiHong1");
  //cout << n << endl;
  //for_each(studentSocres.begin(), studentSocres.end(), Display());
  studentSocres.erase(studentSocres.begin(), studentSocres.end());
  for_each(studentSocres.begin(), studentSocres.end(), Display());
  cout << endl;
    return 0;
}

算法

●  STL中算法大致分为4类:包含于<algorithm> <numeric> <functional>


   ○  非可变排序算法:指的是不直接修改其操作的容器内容的算法

   ○  可变排序算法:修改他们操作的容器内容的算法

   ○  排序算法:包括堆序列进行排序和合并的算法,搜索算法以及有序序列上的集合操作

   ○  数值算法:对容器内容进行数值计算


●  最长见的算法包括:


   查找、排序和通用算法,排列组合算法,集合算法等

#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include<iostream>
using namespace std;
int main()
{   
  // transform和lambda表达式
  int ones[] = { 1, 2, 3, 4, 5 };
  int twos[] = { 10, 20, 30, 40, 50 };
  int results[5];
  transform(ones, ones + 5, twos, results, std::plus<int>()); // 数组元素依次相加并返回
  for_each(results, results + 5,
    [ ](int a)->void {
    cout << a << endl; } ); // lambda表达式(匿名函数)
  cout << endl;
  // find
  int arr[] = { 0, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8 };
  int len = sizeof(arr) / sizeof(arr[0]);
  vector<int> iA(arr + 2, arr + 6);   // {2,3,3,4}
  //vector<int> iA;
  //iA.push_back(1);
  //iA.push_back(9); // {1, 9}
  cout << count(arr, arr + len, 6) << endl; // 统计6的个数
  cout << count_if(arr, arr + len, bind2nd(less<int>(),  7) ) << endl; // 统计<7的个数
  cout << binary_search(arr, arr + len, 9) << endl;   // 9找不到
  cout << *search(arr, arr + len, iA.begin(), iA.end()) << endl; // 查找子序列
  cout << endl;
    return 0;
}
#include <algorithm>
#include <iostream>
using namespace std;
// 输入一个不存在重复字符的字符串,打印出字符串中字符的全排列。
//比如:
//输入: "123"   3*2*1 = 3!
//输出:  123
//          132
//          213
//          231
//          321
//          312
//f(123) = 1+f(23), f(23) = 2+f(3), f(3)  = 3  递归
void swap(char* a, char* b)
{
  char temp = *a;
  *a = *b;
  *b = temp;
}
void Permutation(char* pStr, char* pPostion)
{
  // 基准点
  if (*pPostion == '\0')
  {
    cout << pStr << endl;
  }
  else
  {
    for (char* pChar = pPostion; *pChar != '\0'; pChar++)
    {
      // 依次和后面的字符交换
      swap(*pChar, *pPostion);
      Permutation(pStr, pPostion + 1);
      // 换回来
      swap(*pChar, *pPostion);
    }
  }
}
int main()
{
  char test[] = "132";
  Permutation(test, test);
  cout << endl;
  // 用STL输出全排列
  // 注意:必须要保证数组顺序,
  do
  {
    cout << test[0] << test[1] << test[2] << endl;
  } while (next_permutation(test, test + 3));
  cout << endl;
  char test2[] = "321";
  // 注意:必须要保证数组顺序,
  do
  {
    cout << test2[0] << test2[1] << test2[2] << endl;
  } while (prev_permutation(test2, test2 + 3));
    return 0;
}

迭代器

●  是一种smart point,用于访问顺序容器和关联容器中的元素,相当于容器和操作容器的算法之间的中介


●  迭代器按照定义方式分为四种:


1.正向迭代器:iterator

2.常量正向迭代器:const_iterator

3.反向迭代器:reverse_iterator

4.常量反向迭代器:const_reverse_iterator

#include <list>
#include <iostream>
using namespace std;
int main()
{
  list<int> v;
  v.push_back(3);
  v.push_back(4);
  v.push_front(2);
  v.push_front(1);  // 1, 2, 3, 4
  list<int>::const_iterator it;
  for (it = v.begin(); it != v.end(); it++)
  {
    //*it += 1;
    cout << *it << " ";
  }
  cout << endl;
  // 注意:迭代器不支持<
  //for (it = v.begin(); it < v.end(); it++)
  //{
  //  cout << *it << " ";
  //}
  cout <<v.front() << endl;
  v.pop_front();  // 从顶部去除
  list<int>::reverse_iterator it2;
  for (it2 = v.rbegin(); it2 != v.rend(); it2++)
  {
    *it2 += 1;
    cout << *it2 << " ";                          // 5 4 3
  }
  cout << endl;
    return 0;
}

适配器

●  stack 栈:一种先进后出的容器,底层为deque

●  queue 队列:一种先进先出的容器,底层为deque

●  priority_queue 优先队列:一种特殊的队列,他能够在队列中进行排序(堆排序),底层实现结构式vector或者deque

#include <functional>
#include <stack>
#include <queue>
#include <iostream>
using namespace std;
int main()
{
  //stack<int> s;
  //queue<int> q;
  priority_queue<int> pq;  // 默认是最大值优先
  priority_queue<int, vector<int>, less<int> > pq2; //   最大值优先
  priority_queue<int, vector<int>, greater<int> > pq3; // 最小值优先
  pq.push(2);
  pq.push(1);
  pq.push(3);
  pq.push(0);
  while (!pq.empty())
  {
    int top = pq.top();
    cout << " top is: " << top<< endl;
    pq.pop();
  }
  cout << endl;
  pq2.push(2);
  pq2.push(1);
  pq2.push(3);
  pq2.push(0);
  while (!pq2.empty())
  {
    int top = pq2.top();
    cout << " top is: " << top << endl;
    pq2.pop();
  }
  cout << endl;
  pq3.push(2);
  pq3.push(1);
  pq3.push(3);
  pq3.push(0);
  while (!pq3.empty())
  {
    int top = pq3.top();
    cout << " top is: " << top << endl;
    pq3.pop();
  }
  cout << endl;
    return 0;
}

空间配置器(allocator)

《STL源码分析》

   ●  从使用角度看,allocator隐藏在其他组件中默默工作,不需要关心,但是从stl实现角度看,它是首先分析的组件

   ●  allocator的分析可以提现C++在性能和资源管理上优化思想


jjalloc.h

#pragma once
#ifndef _JJALLOC
#define _JJALLOC
#include<new> //for placement new
#include<cstddef> //for ptrdiff_t ,size_t
#include<cstdlib> //for exit()
#include<climits> //for UINX_MAX
#include<iostream> //for cerr
namespace  JJ
{
  template<class T>
  inline T* _allocate(ptrdiff_t size, T*)
  {
    set_new_handler(0);
    T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
    if (tmp == 0)
    {
      cerr << "out of memory" << endl;
      exit(1);
    }
    return tmp;
  }
  template<class T>
  inline void _deallocate(T* buffer)
  {
    ::operator delete(buffer);
  }
  template<class T1, class T2>
  inline void _construct(T1* p, const T2& value)
  {
    new(p) T1(value);//placement new,invoke constuctor of T1
  }
  template<class T>
  inline void _destroy(T* ptr)
  {
    ptr->~T();
  }
  template<class T>
  class allocator {
  public:
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    //rebind allocator of type U
    template<class U>
    struct rebind {
      typedef allocator<U> other;
    };
    //需要加上以下2个函数,windows的编译器用到了allocator不同类型的拷贝, 
    allocator()
    {
      return;
    }
    template <class U>
    allocator(const allocator<U>& c)
    {
    }
    //hint user for locality,第2个参数是个提示,实现上可能会利用它来增进区域性(locality),或完全忽略之
    pointer allocate(size_type n, const void* hint = 0)
    {
      return _allocate((difference_type)n, (pointer)0);
    }
    void deallocate(pointer p, size_type n)
    {
      _deallocate(p);
    }
    void construct(pointer p, const T& value)
    {
      _construct(p, value);
    }
    void destroy(pointer p)
    {
      _destroy(p);
    }
    pointer address(reference x) { return (pointer)&x; }
    const_pointer const_address(const_reference x) { return (const_pointer)&x; }
    size_type max_size() const {
      return size_type(UINT_MAX / sizeof(T));
    }
  };
}//#end of namespace JJ
#endif
#include "jjalloc.h"
#include <vector>
using namespace std;
int main()
{
  int ia[5] = { 0, 1, 2, 3, 4 };
  unsigned int i;
  vector<int, JJ::allocator<int> > iv(ia, ia + 5);
  for (i = 0; i < iv.size(); i++)
  {
    cout << iv[i] << " ";
  }
  cout << endl;
    return 0;
}

总结

  • STL的六大组件给软件带来了新的多态和复用,是现代C++语言高效的精髓
  • 泛型和STL的学习路线很陡,建议初学者先学会基本的使用和简单的扩展
  • 掌握了一定基础的情况下,可以通过进一步学习和分析源码,编写自己的组件来提升能力


C++多线程

  • C++11中thread的使用
  • mutex等锁的使用
  • 进程与线程,同步与异步
  • 线程交换与移动
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;
mutex g_mutex;
void T1()
{
  g_mutex.lock();
  cout << "T1 Hello" << endl;
  g_mutex.unlock();
}
void T2(const char* str)
{
  g_mutex.lock();
  cout << "T2 " << str << endl;
  g_mutex.unlock();
}
int main()
{
  thread t1(T1);
  thread t2(T2, "Hello World");
  t1.join();
  //t2.join();
  t2.detach();
  cout << "Main Hi" << endl;
    return 0;
}
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
// 存钱
void Deposit(mutex& m, int& money)
{
  // 锁的粒度尽可能的最小化
  for(int index = 0; index < 100; index++)
  {
    m.lock();
    money += 1;
    m.unlock();
  }
}
// 取钱
void Withdraw(mutex& m, int& money)
{
  // 锁的粒度尽可能的最小化
  for (int index = 0; index < 100; index++)
  {
    m.lock();
    money -= 2;
    m.unlock();
  }
}
int main()
{
  // 银行存取款
  //int money = 2000;
  //mutex m;
  //cout << "Current money is: " << money << endl;
  //thread t1(Deposit, ref(m), ref(money));
  //thread t2(Withdraw, ref(m), ref(money));
  //t1.join();
  //t2.join();
  //cout << "Finally money is: " << money << endl;
  //线程交换 
  //thread tW1([]()
  //{
  //  cout << "ThreadSwap1 " << endl;
  //});
  //thread tW2([]()
  //{
  //  cout << "ThreadSwap2 " << endl;
  //});
  //cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
  //cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
  //cout << "Swap after:" << endl;
  //swap(tW1, tW2); 
  //cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
  //cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
  //tW1.join();
  //tW2.join();
   线程移动
  thread tM1( []() { ; } );
  //tM1.join();
  cout << "ThreadMove1' id is " << tM1.get_id() << endl;
  cout << "Move after:" << endl;
  thread tM2 = move(tM1);
  cout << "ThreadMove2' id is " << tM2.get_id() << endl;
  cout << "ThreadMove1' id is " << tM1.get_id() << endl;
  tM2.join();
  return 0;
}


目录
相关文章
|
4月前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
84 2
|
2月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
372 67
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
92 0
|
6月前
|
编译器 C++ 开发者
C++一分钟之-C++20新特性:模块化编程
【6月更文挑战第27天】C++20引入模块化编程,缓解`#include`带来的编译时间长和头文件管理难题。模块由接口(`.cppm`)和实现(`.cpp`)组成,使用`import`导入。常见问题包括兼容性、设计不当、暴露私有细节和编译器支持。避免这些问题需分阶段迁移、合理设计、明确接口和关注编译器更新。示例展示了模块定义和使用,提升代码组织和维护性。随着编译器支持加强,模块化将成为C++标准的关键特性。
397 3
|
2月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
291 12
|
1月前
|
消息中间件 存储 安全
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
65 2
|
3月前
|
存储 算法 C++
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
文章详细探讨了C++中的泛型编程与STL技术,重点讲解了如何使用模板来创建通用的函数和类,以及模板在提高代码复用性和灵活性方面的作用。
64 2
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
|
2月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
90 11
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
48 9