目录
一、前言
C++学过很多遍了,不用总是忘,知识基础运用,通过运用可以很快了解如何使用
二、C++ 基础
俗话说得好,空谈误国,实干兴邦,便回顾便实战可以随时验证所学,融会贯通
2.1 源文件
humanbeing.cpp
#include <iostream>
#include "humanbeing.hpp"
HUM::Brain::Brain(int sec,int think):m_secret(sec),m_think(think)
{
//this 指向当前对象,它是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this
std::cout<<"m_secret:"<< m_secret <<std::endl;
this->m_cal = this->m_secret+m_think;
}
HUM::Brain::~Brain(){
float image = 12.7654321;
/*强制类型转换:
static_cast 不能用于无关类型之间的转换,如不同的类型指针,数据存储格式不一样
const_cast用于去掉 const 和 volatile 修饰
reinterpret_cast 高风险,补充static_cast,如具体类型指针转换
dynamic_cast 类继承之间类型转换,向上向下均可
*/
m_think = static_cast<int>(image);
std::cout.precision(3);
std::cout<<"I'm not gonna think: "<< image <<std::endl;
}
int HUM::Brain::add (int a,int b)
{
return a+b;
}
void HUM::Brain::why(int a ,int b,int c)
{
if(this->add(a,b) == c)
{
std::cout<<"you are celver:"<< add(a,b) <<std::endl;
}
else
{
std::cerr<<"you are stupid:"<< add(a,b) << std::endl;
}
}
/*引用*/
void HUM::Brain::swap(int &a, int &b)
{
std::cout<<"before a:"<< a <<" b:" << b << std::endl;
int tem = b;
b = a;
a = tem;
}
void HUM::Brain::pstrTrans(Brain* &pbr)
{
std::cout<<"&引用传指针* m_think:"<< pbr->m_think << std::endl;
}
/*const 在前修饰返回值,在后修饰成员函数针对成员变量; const对象只能访问const成员;*/
int HUM::Brain::getMySecret() const
{
std::cout<<"my secret: "<< m_secret << std::endl;
return this->m_secret;
}
void HUM::Brain::staticThinking()
{
std::cout<<"I need "<< HUM::Brain::ms_area <<" hours to thinking"<< std::endl;
}
//友元
void HUM::freeFunc(Brain* pBrn)
{
std::cout<<"I'm your friend,your sceret is "<<pBrn->m_secret<<std::endl;
}
void HUM::Brain::introduceFriends(Animal* pani)
{
std::cout<<"My friends have legs "<<pani->m_leg <<std::endl;
}
void HUM::Brain::getFriendsDetail(Animal* pani)
{
std::cout<<"My friends have child "<<pani->m_children <<std::endl;
}
male.cpp
#include "male.hpp"
#include <iostream>
HUM::Male::Male(int sec,int think,int age):Brain(sec,think),m_age(age)
{
std::cout<<" Male 类 构造"<<std::endl;
}
nature.cpp
#include <iostream>
#include "nature.hpp"
HUM::Animal::Animal(int legs):m_leg(legs)
{
m_children = 3;
std::cout<<"the animal have legs " <<m_leg<<std::endl;
}
main.cpp
#include <iostream>
#include "humanbeing.hpp"
#include "nature.hpp"
#include "male.hpp"
#include <typeinfo>
int HUM::Brain::ms_area = 5;
int main(int argc,char*argv[]){
int a = 6;
int b = 2;
char sumAB = 13;
HUM::Brain *phb = new HUM::Brain(3,4);
std::cout<<"input a number:"<<std::endl;
//std::cin.getline(&sumAB,5);
std::cout<<"the a number is:"<< static_cast<int>(sumAB) <<std::endl;
phb->why(phb->ms_area,7,static_cast<int>(sumAB));
std::cout<<"think: "<<phb->m_think<<std::endl;
std::cout<<"a+b = "<<phb->add(a,b)<<std::endl;
phb->why(a,b);
phb->swap(a,b);//引用
phb->pstrTrans(phb);
std::cout<<"after a:"<< a <<" b:" << b << std::endl;
phb->getMySecret();
HUM::Brain::staticThinking();
//友元
HUM::freeFunc(phb);
HUM::Animal dog(7);
phb->introduceFriends(&dog);
phb->getFriendsDetail(&dog);
delete phb;
//继承
int age = 18;
HUM::Male boy(a,b,age);
boy.Brain::getMySecret();//子类访问基类的方法
//typeid使用方法
//获取一个字面量的类型信息
const type_info& dInfo = typeid(25.65);
std::cout << dInfo.name() << " | " << dInfo.raw_name() << " | " << dInfo.hash_code() << std::endl;
//流
//输出单个字符,ASCII码 put
std::cout.put(71).put(79).put(79).put(68).put('\n');
//向输出缓冲区添加指定字符串 write
std::cout.write("http://", 7).write("c.biancheng.net", 15).write("/cplus/", 7).write("\r\n",4);
//tellp seekp 读取或修改位于输出缓冲区的数据
return 0;
}
2.2 头文件
humanbeing,hpp
#ifndef HUMANBEING
#define HUMANBEING 1
#include "nature.hpp"
class Animal;
namespace HUM{
class Brain{//默认成员都是private, struct默认是public
public:/*都可以访问*/
int m_think;
int m_cal;
int m_rat;
public:/*静态变量:实现多个对象共享数据的目标,类或者对象访问*/
static int ms_area;
private:/*成员函数中访问,子类、类外不能访问*/
int m_secret;
protected:/*子类、成员函数都可以访问,类外无法访问*/
int m_littleBrain;
public:
Brain(int sec,int think);
~Brain();
int add (int a,int b);/*类内的成员函数可以相互调用,访问*/
void why(int a ,int b,int c = 8);
void swap(int &a, int &b);/*引用传参: 数据别名*/
void pstrTrans(Brain* &pbr);/*引用传递对象指针类型*/
/*int& q[10] ;//q首先向右结合,所以这个相当于 (int&)q[] q是个数组,其中的元素是引用,叫引用的数组
int(&p)[10] ;p首先和&结合,所以p是引用,引用的对象是数组,叫作数组的引用
*/
public:
int getMySecret() const;/*const 修饰成员函数,不能改变成员的值*/
public: /*静态成员函数只能访问静态成员(没有this指针),类直接调用*/
static void staticThinking();
public:/*友元函数可以独立,也可以是其他类成员函数,友元函数可以访问类所有成员*/
friend void freeFunc(Brain* pBrn);
/*两个文件的友元函数要相互添加.hpp文件*/
void introduceFriends(Animal* pani);
void getFriendsDetail(Animal* pani);
};
void freeFunc(Brain* pBrn);
}
#endif
male.hpp
#ifndef MALE
#define MALE 1
#include "humanbeing.hpp"
namespace HUM{
class Male : public Brain
{
public:
int m_age;
int m_height;
int m_weight;
using Brain::m_littleBrain;//protected 权限改为 public
public:
/*对任意一个类,默认的构造函数,拷贝构造函数,析构函数如下:
1 A(void); // 缺省的无参数构造函数
// 缺省的拷贝构造函数,只有单个形参,形参为对本类类型对象的引用(用const修饰)
//拷贝是在 【初始化】 阶段(类A a2 = a1)进行的,非初始化阶段赋值调用重载运算符=
//也就是用其它对象的数据来初始化新对象的内存,针对有指针类型变量的类
2 A(const A &a);
3 ~A(void); // 缺省的析构函数
4 A & operate =(const A &a); // 缺省的赋值函数
*/
Male(int sec,int think,int age);
/*派生类如果有与基类同名的函数,则回覆盖基类的函数,使用自己的函数
*/
/*虚继承可以解决菱形问题A->B , A-> C , B C ->D, 比如iostream 是从istream 和ostream继承得来,它俩从base_ios继承
* 虚继承可以保留一份虚基类的成员,不回产生二义性。
* 强制类型转换,遵循向上转型,转型后只能访问基类继承的成员
*/
/*虚函数:基类指针只能访问派生类成员变量,不能访问派生类成员函数
* 基类指针指向基类就访问基类成员,指向派生类就访问派生类,现象叫多态
*/
/*纯虚函数:virtual 返回值类型 函数名 (函数参数) = 0;
* 纯虚函数的类叫抽象类,抽象类是类型,让派生类实现纯虚函数
*/
};
}
#endif
nature.hpp
#ifndef NATURE
#define NATURE 1
#include "humanbeing.hpp"
namespace HUM{
class Animal
{
public:
int m_leg;
public:
friend class Brain;//友元类
private:
int m_children;
public:
Animal(int legs);
friend void introduceFriends(Animal* pani);//友元函数
};
}
#endif
2.3 CmakeLists
cmake_minimum_required(VERSION 3.0)
project(reviewcpp
VERSION 1.0
DESCRIPTION "know how to use cmake"
#LANGUAGES CXX #指定编程语言为CPP, 默认是CXX C
)
#add
aux_source_directory(./src SRC_DIR)
include_directories(./inc)
#exe
add_executable(cpprun ${SRC_DIR})
三、C++ STL
stand template library标准模板库通过模板实现了常用的数据结构算法,做到了算法和数据结构的分离。vector 的底层为顺序表(数组),list 的底层为双向链表,deque 的底层为循环队列,set 的底层为红黑树,hash_set 的底层为哈希表
3.1 模板文件
tempt.hpp中定义
#ifndef TMPT
#define TMPT
//函数模板
/*
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
template <class T> void swap(T& a, T& b){},
*/
//类模板
/*
template<class 形参名,class 形参名,…> class 类名
{ ... };
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
template<class T1,class T2> void A<T1,T2>::h(){};
*/
template<class T>
class Aba{
public:
T g(T a,T b);
Aba();
};
#endif
3.2 STL源文件
/*
迭代器(指针):运用泛型技术隐藏不同容器内部差异,实现统一接口传送数据,遍历读写数据
输入迭代器,输出迭代器,前向迭代器fd,双向迭代器dd,随机访问迭代器rd
stack和queue不支持迭代器
容器类名::iterator 迭代器名; 常量正向迭代器const_iterator,反向迭代器 reverse_itertor,常量反向迭代器const_reverse_iterator
*/
/*
序列容器:
array ,长度固定不变
vector(rd),长度可变,尾部增加或删除元素效率高
deque(rd),支持高效尾部头部增加删除元素
list(dd),可变,任何地方增加删除元素高效,访问元素比前3个慢
forward_list, 正向链表,类似list,访问只能从第一个开始,比list块、节省内存
关联容器<key,value>:排序容器(从小到大)set(dd),multiset,map(dd),multimap;快速查找、读取删除,插入元素效率高于序列容器
哈希容器unordered_set(fd),unordered_multiset(fd),unordered_map(fd),unordered_multimap(fd)
*/
#include <iostream>
#include <array>
#include <vector>
#include <map>
#include "tmpt.hpp"
#include <deque>
#include <list>
#include <forward_list>
#include <iterator>
#include <utility>
#include <string>
#include <map>
#include <functional> //std::greater ,std::less
#include <set>
#include <unordered_map>
#include <stack>
#include <queue>//priority_queue
#include <algorithm>
#include <unordered_set>
using uint_t = unsigned int;
using map_int_t = std::map<std::string,int>;
using func_t = void(*)(int,int); //typedef void(*func_t)(int,int)
template<class T> class A{
public:
T g(T a,T b){return a+b;}
A(){std::cout<< "tem a out" <<std::endl;}
};
//tmpt.hpp
template<class T> Aba<T>::Aba(){std::cout<< "tem a out" <<std::endl;}
template<class T> T Aba<T>::g(T a,T b)
{
return a+b;
}
class CopyReg{
public:
bool operator()(const int& i)
{
return(i%2==1);
}
};
int main(int argc,char* argv[])
{
//template
Aba<int> a;
std::cout<< "template call:"<<a.g(2,3) <<std::endl;
int i = 0;
//----------- array -------------------
std::array<double,10> box;//不能用push_back
//std::array<double,10>::iterator ibox;
for(auto ibox = box.begin();ibox!=box.end();ibox++,i++)
{
box[i] = i;
//std::cout<<box.at(i)<<std::endl;//box[i]
//std::cout<< *ibox <<std::endl;
box.at(i)+=3;//at避免越界访问
}
for(auto& v :box )//每一个元素的引用
{
v = v+1;
//std::cout<< "v: "<< v <<std::endl;
}
box.fill(7.7);//填充所有元素
std::cout<<"box back: "<<box.back()<<std::endl;//front
std::cout<<"box length: "<<box.size()<<std::endl;
auto first_it = box.begin();
auto last_it = box.end();
while(first_it !=last_it)
{
*first_it = i;
//std::cout<< *first_it <<std::endl;
++first_it;
i++;
}
//----------- vector -------------------
std::vector<uint_t> vec(10,0);
std::vector<uint_t> vct;
for(auto i = 0;i<5;i++)
vct.push_back(i);//从队尾追加,先创建再拷贝或移动到容器中
for(auto i = 0;i<5;i++)
vct.emplace_back(i);//从队尾追加,直接在容器尾部创建元素,优先使用emplace_back
//删除
vct.pop_back();//队尾删除
vct.erase(vct.begin()+3);
std::cout<<"befor :"<<vct.capacity()<<std::endl;
vct.shrink_to_fit();//将内存减少到等于当前元素实际所使用大小
std::cout<<"after :"<<vct.capacity()<<std::endl;
std::swap(vec,vct);
vec.at(2) = 77;//支持防止越界访问at
vec.insert(vec.begin()+2,3);//第一个参数是迭代器,insert支持插入容器和多个元素
vec.emplace(vec.end()-2,7);//emplace只允许一次插入一个元素,而不是多个
for(auto &v : vec)//每个元素引用
{
v+=2;
//std::cout<< "v:vec "<<v<<std::endl;
}
std::cout<< "vec:front "<<vec.front()<<std::endl;//队头, back()队尾
vec.clear();
vct.clear();//移出所有元素,大小为0
//----------- deque -------------------double ended queue: 不保证所有元素存储连续空间中;remove所有相等元素
std::array<int,5> ar{1,2,3,4,5};
std::deque<int> dq(ar.begin()+2,ar.end());
dq.pop_back();
dq.pop_front();
dq.push_back(7);
dq.push_front(8);
for(auto& d: dq)
{
//std::cout<< "d:dq "<< d <<std::endl;
}
dq.clear();
//----------- list -------------------双向列表,两端可以快速删除插入,访问元素慢
/*
remove_if:删除满足条件的元素
unique:删除相邻重复元素,只保留一个
merge:合并已排序list容器
sort:排序(默认从小到大)
*/
std::list<int> vlist(3,6);
vlist.push_back(7);
for(std::list<int>::iterator it = vlist.begin();it !=vlist.end();it++)
{
//std::cout<< "L:list "<< *it <<std::endl;
}
vlist.clear();
//----------- forward list -------------------高效的list,前向链表,不提供size()
std::forward_list<int> vFL(3);
vFL.push_front(1);
vFL.push_front(11);
vFL.push_front(111);
int vfsize = std::distance(std::begin(vFL),std::end(vFL));
std::cout<< "FL:list size "<< vfsize <<std::endl;
auto it = vFL.begin();
advance(it, 1);//移动迭代器
while (it!=vFL.end())
{
std::cout << *it << " ";
++it;
}
vFL.clear();
//----------- pair-------------------#include <utility> 键值对,<first, second>
//make_pair返回一个pair对象,是一个临时对象,右值引用 调用移动构造函数
std::pair <std::string, std::string> pair1(std::make_pair("C++", "http://c.biancheng.net/cplus/"));
std::pair<std::string,std::string> pair2 = std::make_pair("C++", "hello world");
std::cout << "pair2: " << pair2.first << " " << pair2.second << std::endl;
//----------- map-------------------
/*
键是唯一的;根据键大小进行排序,
默认std::less<T>;设置为std::greater<T>
map的元素是pair类对象;
lower_bound(key)不小于key的键值对迭代器
upper_bound(key)大于key的键值对迭代器
*/
std::map<std::string, int,std::greater<std::string> > myMap;
myMap.emplace("job1",8500);
myMap.emplace("job2",20000);
myMap.emplace("job3",16000);
if(!myMap.empty())
{
for(auto it = myMap.begin();it != myMap.end();it++)
{
std::cout<<it->first<<" "<<it->second<<std::endl;
}
}
// multimap 键可以重复
//----------- set -------------------
/*
键值完全相同,值不能重复,根据键大小进行排序
修改元素的方法,先删除,再添加
*/
std::set<std::string> myset{"http://c.biancheng.net/java/","http://c.biancheng.net/stl/"};
myset.insert("http://c.biancheng.net/python/");
for(auto it = myset.begin();it!=myset.end();it++)
std::cout<< *it <<std::endl;
//multiset 值可以重复
//----------- unordered_map -------------------
/*无序容器内部存储的键值对是无序的,各键值对的存储位置取决于该键值对中的键
无序容器擅长通过指定键查找对应的值,不擅长遍历容器
不会对键值对排序
*/
std::unordered_map<std::string, std::string> my_uMap{
{"C","http"} };
auto itP2 = my_uMap.insert(pair2);
//查找指定键对应的值,效率比关联式容器高
std::string str = my_uMap.at("C");
std::cout << "str = " << str << std::endl;
//----------- 容器适配器 -------------------
/*将不适用的转化为可用
stack栈适配器:默认deque,满足条件vector,deque,list;单端口容器(栈顶),先进后出,push,pop,top,size
queue队列适配器:默认deque,满足条件deque,list
priority_queue优先权队列适配器:默认vector,满足条件vector,deque, First In Largest Out
*/
std::list<int> temL{1,2,3};
std::stack<int,std::list<int>> myStack(temL);
while(!myStack.empty())
{
//std::cout<<myStack.top()<<std::endl;
myStack.pop();
}
std::array<int,4> temA{ 4,1,3,2 };
std::priority_queue<int>myPQ(temA.begin(),temA.end());//{4,2,3,1}
while(!myPQ.empty())
{
std::cout << myPQ.top()<<" ";
myPQ.pop();//移除队头元素的同时,将剩余元素中优先级最大的移至队头
}
//----------- 迭代器适配器 -------------------
/*
reverse_iterator:逆向迭代器 ++ --, 反向迭代器内部互换了 ++ 和 --
insert_iterator:在容器任何位置添加新的元素
istream_iterator:用于从文件或者键盘读取数据
move_iterator:将某个范围的类对象移动到目标范围,而不需要通过拷贝移动
*/
std::reverse_iterator<std::list<int>::iterator> rb = temL.rbegin();
std::reverse_iterator<std::list<int>::iterator> re = temL.rend();
while (rb != re) {
std::cout << *rb << " ";
++rb;
}
//----------- 常用算法 -------------------
/*http://c.biancheng.net/view/7493.html
find_if:在容器中查找满足条件的元素迭代器索引
search:在序列 A 中查找序列 B 第一次出现的位置
binary_search:查找指定区域内是否包含某个目标元素,二分法
copy_if:过滤器
unique:可以在序列中原地移除重复的元素,常和std::erase搭配
rotate:如何旋转序列
transform:将函数应用到序列的元素上,并将这个函数返回的值保存到另一个序列中
replace:用新的值来替换和给定值相匹配的元素
*/
std::vector<int> vecG{4,2,3,1,5};
std::vector<int>::iterator vit = std::find_if(vecG.begin(),vecG.end(),CopyReg());
std::cout << "find_if: "<<*vit << std::endl;
std::vector<std::string> names {"A1", "Beth", "Carol", "Dan", "Eve","Fred", "George", "Harry", "Iain", "Joe"};
std::unordered_set<std::string> more_names {"Jean", "John"};
size_t max_length{4};
std::copy_if(std::begin(names),
std::end(names),
std::inserter(more_names, std::begin(more_names)),
[max_length](const std::string& s) { return s.length() <= max_length;});
return 0;
}
CMakeLists.txt与第二节使用的相同