嵌入式C++(六)

简介: 嵌入式C++(六)

一 类模板


(1)概念


类模板中定义的函数参数类型或者属性等数据类型可以参数化。


template <typename 类型参数1,typename 类型参数2,...>
class 类型{
  //...
}


#include <iostream>
using namespace std;
template <typename T,typename U>
class Test
{
private:
  T a;
  U b;
public:
  Test(T a, U b)
  {
  this->a = a;
  this->b = b;
  }
  void show()
  {
  cout << a << " " << b << endl;
  }
};
int main(int argc,char*argv[])
{
  //Test t(1, 'a');  
  Test<int, char> t(1, 'a');  //类模板创建一定要显示调用
  t.show();
  return 0;
}


(2)模板类的继承


#include <iostream>
using namespace std;
template <typename T>
class  Parent
{
protected:
  T a;
public:
  Parent(T a)
  {
  this->a = a;
  }
  void show()
  {
  cout << a << endl;
  }
};
class Child:public Parent<int>  //模板类派生普通类,继承的同时对基类实例化
{
public:
  Child(int a) :Parent(a)
  {
  }
  void show()
  {
  cout << a << endl;
  }
};
template <typename T,typename U>
class Child2 :public Parent<T>   //模板类派生模板类,继承的同时不需要对parent实例化
{
private:
  U b;
public:
  Child2(T a, U b) :Parent<T>(a)
  {
  this->b = b;
  }
  void show()
  {
  cout << this->a << " " << this->b << endl;
  }
};
int main(int argc,char*argv[])
{
  Child c1(1);
  c1.show();
  Child2<int, double> c2(1, 1.11);
  c2.show();
  return 0;
}


(3)模板类的声明


#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
  Test(T a);
  void show();
  ~Test();
protected:
private:
  T a;
};
template <typename T>
Test<T>::Test(T a)  //Test<T>表示Test是模板类,不是普通类
{
  this->a = a;
}
template <typename T>
void Test<T>::show()
{
  cout << a << endl;
}
template <typename T>
Test<T>::~Test()
{
}
int main(int argc,char*argv[])
{
  return 0;
}



(4) 模板类中的static


#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
  Test(T a);
  void show();
  ~Test();
protected:
private:
  T a;
public:
  static int count;
};
template <typename T>
int Test<T>::count = 0;
template <typename T>
Test<T>::Test(T a)  //Test<T>表示Test是模板类,不是普通类
{
  this->a = a;
  count++;
}
template <typename T>
void Test<T>::show()
{
  cout << a << endl;
}
template <typename T>
Test<T>::~Test()
{
}
int main(int argc,char*argv[])
{
  Test<int> t1(1);
  Test<int> t2(1);
  Test<int> t3(1);
  Test<int> t4(1);
  Test<int> t5(1);
  Test<char> t6('a');
  Test<char> t7('a');
  Test<char> t8('a');
  cout << Test<int>::count << endl;
  cout << Test<char>::count << endl;
  return 0;
}


二 成员模板


2.1 为什么要使用成员模板


#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
  T m_a;
public:
  void print(const Test<T> &a)
  {
  cout << a.m_a << endl;
  }
};
int main(int argc,char *argv[])
{
  Test<int> a;
  a.m_a = 1;
  Test<double> b;
  b.m_a = 1.123;
  a.print(a);
  a.print(b);
  return 0;
}


2.2 成员模板的实现


#include <iostream>
using namespace std;
//template <typename T,typename U>
template <typename T>
class Test
{
public:
  T m_a;
public:
  template <typename X>
  void print(const Test<X> &a)
  {
  cout << a.m_a << endl;
  }
};
int main(int argc,char *argv[])
{
  Test<int> a;
  a.m_a = 1;
  Test<double> b;
  b.m_a = 1.123;
  a.print(a);
  a.print(b);
  return 0;
}


三 关键词-typename


3.1 内嵌依赖类型名


内嵌:是指在类的内部定义的

依赖:依赖于摸一个模板参数

类型名:最终要指出的这个类型名


3.2 实例


#include <iostream>
using namespace std;
//template <typename T,typename U>
template <typename T>
class Test
{
public:
  T m_a;
  typedef T* PT;   //实际上就是一个内嵌依赖类型名
  //static int PT;
public:
  template <typename X>
  void print(const Test<X> &a)
  {
  cout << a.m_a << endl;
  }
};
int main(int argc,char *argv[])
{
  int num = 100;
  //typename Test<int>::PT p = &num;
  Test<int>::PT p = &num;
  return 0;
}


四 using 给模板起别名


#include <iostream>
using namespace std;
//template <typename T,typename U>
template <typename T,typename X>
class Test
{
public:
  T m_a;
  typedef T* PT;   //实际上就是一个内嵌依赖类型名
  //static int PT;
public:
};
template <typename S>
using MyA = Test<string, S>;  //将两个参数降为一个参数
using s32 = int;
using P_func = void(*)(int, int);
int main(int argc,char *argv[])
{
  Test<string, int> a;
  MyA<int> a2;
  return 0;
}


五 实例化


5.1 #pragma once


1、ifndef方法是c/c++的标准支持,比较常用的方式
#pragma once一般由编译器提供保证,功能是保证同一个文件不会被包含多次
visual studio 2017之后的版本新建头文件都会自带#pragma once
2、兼容性:#pragma once产生于ifndef之后,ifndef不受任何编译器的限制,而#pragma once方法有些编译器不支持(较老的编译器(gcc3.4之前的不支持)),兼容性不够好,
3、ifndef可以针对文件中的一部分代码,而#pragma once只针对整个文件
4、ifndef 更加灵活,兼容性好,#pragma once操作简单,效率更高。


5.2 隐式实例化


隐式实例化是指在函数调用的时候,如果没有发现与之相匹配的函数存在,编译器会寻找同名的函数模板,如果可以成功进行参数的推演,就对函数模板实例化。

类模板同上。


5.3 显示实例化


显示实例化:外部实例化,在不发生函数调用的时候将函数模板实例化

类模板同上。


5.3.1 函数模板的显示实例化


template [返回值类型] [函数名]<实际类型列表>(函数参数列表)

template void func(const int&);


5.3.2 类模板的显示实例化


template class Test;
作用:减少隐式实例化实例多个函数和类的开销,只实例化一次(不同编译器处理机制可能不同)


#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
void print(const T &t)
{
  cout << t << endl;
}
template <typename T,typename CONT = vector<T>>
class Stack
{
public:
  Stack()
  {
  top = -1;
  }
  void push(T num)
  {
  data.push_back(num);
  }
  void pop()
  {
  //return data.pop_back();
  }
  int top;
  CONT data;    //vector<T> data;
};


#include "template.h"
template void print<int>(const int &t); //显示实例化,只实例化一次
template class Stack<int, vector<int>>;
void Func()
{
  print(5);
  print("hello");
  print(10);
  Stack<int> s;
  Stack<string> s1;
}


#include "template.h"
extern void Func();
template void print<int>(const int &t); //显示实例化,只实例化一次
int main(void)
{
  print(5);
  print("hello");
  print(10);
  Stack<int> s;
  Stack<string> s1;
  Func();
}


5.4 模板全特化和偏特化


5.4.1 为什么要模板特化?


因为编译器认为,对于特定的类型,如果你能对某一个功能更好的实现,那么就该听你的
模板实例化时会优先匹配“模板参数”最符合那个特化的版本
模板特化的前提已要求模板的泛化



(1) 类模板的全特化

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
  A()
  {
  }
  int m_a;
};
template <typename T,typename U>
class Test
{
public:
  T m_a;
  U m_b;
public:
  void print()
  {
  cout << m_a << endl;
  cout << m_b << endl;
  }
};
//模板特化的作用:处理一些模板处理不了或者处理不好的数据和方法,需要将这些类型特例化,按照特例化的方法处理
//类的全特化:全部类型全部指定
template<>
class Test<A, string>
{
public:
  A  m_a;
  string m_b;
public:
  void print()
  {
  cout << "class Test<A, string>" << endl;
  cout << m_a.m_a << endl;
  cout << m_b << endl;
  }
};
int main(void)
{
  Test<int, string> a;
  a.m_a = 1;
  a.m_b = "helloworld";
  a.print();
  A tb;
  Test<A, string> s1;
  s1.m_a = tb;
  s1.m_b = "world";
  s1.print();
  return 0;
}


(2) 类模板的偏特化

模板参数数量偏特化


#include <iostream>
#include <string>
using namespace std;
class A
{
public:
  A()
  {
  }
  int m_a;
};
template <typename T,typename U>
class Test
{
public:
  T m_a;
  U m_b;
public:
  void print()
  {
  cout << m_a << endl;
  cout << m_b << endl;
  }
};
//通过减少类模板参数,实现类模板的偏特化
template<typename T>
class Test<T, string>
{
public:
  T  m_a;
  string m_b;
public:
  void print()
  {
  cout << "class Test<T, string>" << endl;
  cout << m_a << endl;
  cout <<"name:"<<m_b << endl;
  }
};
int main(void)
{
  Test<int, string> a;
  a.m_a = 1;
  a.m_b = "helloworld";
  a.print();
  /*a tb;
  test<a, string> s1;
  s1.m_a = tb;
  s1.m_b = "world";
  s1.print();*/
  return 0;
}


(3)类模板参数范围偏特化


int --->const int   T -->T*   T--->T&
1
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
  A()
  {
  }
  int m_a;
};
template <typename T,typename U>  //可通过将其改为const,指针,引用等降低其范围
class Test
{
public:
  T m_a;
  U m_b;
public:
  void print()
  {
  cout << m_a << endl;
  cout << m_b << endl;
  }
};
//通过减少类模板参数,实现类模板的偏特化
template<typename T,typename U>
class Test<const T, const U>
{
public:
  T m_a;
  U m_b;
public:
  void print()
  {
  cout << "class Test<const T, const U>" << endl;
  }
};
int main(void)
{
  Test<const int, const int> a1;
  a1.print();
  return 0;
}


六 内存管理


6.1 c++内存管理


大多数问题都是由于内存泄漏导致的。


6.2 内存分析诊断工具 valgrind


sudo apt-get update
sudo apt-get install -f
sudo apt-get intall valgrind


使用 valgrind:


0a2653c851af460fa595bd959398a8f1.png


6.3 如何避免内存泄漏


new/delete的成对使用
new[]/delete[]成对出现
人为的控制new/delete的问题,无法杜绝内存泄漏


6.4 c++为什么没有提供GC机制(垃圾回收机制)


没有共同基类:c++是从c语言发展而来,允许直接操作指针,允许将一个类型转换位另一个类型
对于一个指针无法知道它真正指向的类型,而java和c#都有一个共同的基类。
系统开销:GC机制所带来的系统开销,违反了c++的设计哲学--》不为不必要的功能支持代价,不符合c++高效的特性,不符合底层工作的要求。
消耗内存:c++产生的年代内存比较小
替代方法:c++有析构函数,智能指针,引用计数器等去管理资源的释放。


6.5 智能指针


6.5.1 作用


帮助开发者动态的开辟和释放申请的空间,能有效的防止内存泄漏。


6.5.2 分类


分类:
  auto_ptr(c++98): 被c++11智能指针替代,不再使用
    unique_ptr(c++) 独占指针
    share_ptr(c++):共享指针
    weak_ptr(c++):弱指针 
    int *p:裸指针


6.5.3 share_ptr


共享式指针:


多个指针可以同时指向一个对象(共享所有权,协同工作)
当最后一个指针被销毁或者指向其它对象时,这个对象会被释放


工作原理:引用计数增加/减少(原子操作)


引用计数增加:
    用一个智能指针初始化另一个智能指针
    函数传参:传递一个智能指针
    函数返回值:返回一个智能指针
引用计数减少:
    给智能指针赋予新值,指向一个新对象
    局部的智能指针离开其作用域。


定义:


share_ptr<指向的类型> 智能指针变量名


#include <iostream>
#include <memory>
#include <string>
using namespace std;
class A
{
public:
  A()
  {
  cout << "A的无参构造" << endl;
  }
  A(int n)
  {
  m_a = n;
  cout << "A的有参构造" << endl;
  }
  int m_a;
  ~A()
  {
  cout << "A的析构函数" << endl;
  }
};
shared_ptr<A> test()
{
  shared_ptr<A> temp(new A);
  return temp;
}
void Func(shared_ptr<A> temp)
{
  cout << temp->m_a << endl;
}
int main(void)
{
  //int *p = new int(5);  //p是裸指针
  //shared_ptr<int> p = new int(5); //初始化:调用类型转换构造函数 explicit
  shared_ptr<int> p(new int(5));
  cout << *p << endl;
  shared_ptr<string> s(new string("helloworld"));
  cout << *s << endl;
  int num = 100;
  //shared_ptr<int> p2(&num);   //智能指针常用于堆空间,指向栈空间的时候,会导致内存释放两次
  //A *pa = new A(100);
  //delete pa;
  shared_ptr<A> pa(new A);
  shared_ptr<A> res = test();
  Func(pa);
  shared_ptr<A> pa2(pa);
  return 0;
}
相关文章
|
5月前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
177 1
|
5月前
|
算法 Linux 程序员
嵌入式工程师以及C++程序员到公司就业需要掌握那些技术?
嵌入式工程师以及C++程序员到公司就业需要掌握那些技术?
|
5月前
|
数据处理 C++ UED
如何作为一个嵌入式软件工程师博主获得铁粉:C/C++ 技术分享之道
如何作为一个嵌入式软件工程师博主获得铁粉:C/C++ 技术分享之道
111 0
|
5月前
|
C语言 数据安全/隐私保护 C++
嵌入式中如何把C++代码改写成C语言代码
嵌入式中如何把C++代码改写成C语言代码
64 0
|
5月前
|
存储 缓存 Java
嵌入式系统中C++内存管理基本方法
嵌入式系统中C++内存管理基本方法
128 0
|
5月前
|
存储 编译器 程序员
嵌入式系统中C++基础知识精髓
嵌入式系统中C++基础知识精髓
103 0
|
5月前
|
关系型数据库 数据库 C++
嵌入式数据库sqlite3【基础篇】基本命令操作,小白一看就懂(C/C++)
嵌入式数据库sqlite3【基础篇】基本命令操作,小白一看就懂(C/C++)
|
5月前
|
存储 编译器 C++
嵌入式中C++ 编程习惯与编程要点分析
嵌入式中C++ 编程习惯与编程要点分析
50 1
|
5月前
|
架构师 数据挖掘 程序员
嵌入式系统中C++ 类的设计和实现分析
嵌入式系统中C++ 类的设计和实现分析
64 1
|
5月前
|
算法 小程序 编译器
嵌入式中C++开发的基本操作方法
嵌入式中C++开发的基本操作方法
56 0