个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

  • CPlusPlus

    • 基础特性

      • 枚举
      • 字符指针
    • vs2019设置
    • C++11特性

    • 并发编程

    • 引用
    • 类和对象
    • 友元和运算符重载
    • 继承
    • 继承和多态
    • 模板
    • C++基础总结
    • 类型转换
    • 异常
    • 容器
    • 算法
    • C++程序设计
      • 转换函数 (conversion function)
      • non-explicit-one-argument ctor
        • conversion function VS. non-explicit-one-argument ctor
        • explicit-one-argument ctor
      • 模板
        • 类模板
        • 函数模板
        • 成员模板
        • 模板特化
        • 模板偏特化
        • 模板模板参数
        • 数量不定的参数模板(varidic template)
      • 仿指针类 (pointer-like classes)
        • 智能指针
        • 迭代器
      • 仿函数类 (function-like classes)
        • 内建函数对象
        • 函数对象适配器
    • C++ Primer总结
    • 编程技巧
    • 标准库体系结构与内核分析
    • 设计模式
    • cmake配置C++工程
    • libcurl的使用总结
    • web开发框架--drogon
    • log4cplus使用
    • C++数据类型
    • 函数
    • 线程
    • 进程
    • 文件操作
    • 日常问题记录
    • Cpp案例程序
    • 多线程
    • 侯捷c++11新特性
    • 侯捷stl
  • Lua技术栈

  • edoyun

  • 内存管理

  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • CPlusPlus
Agnes001
2021-03-27

C++程序设计

# 转换函数 (conversion function)

格式: operator type() const
说明: 要以operator开头,函数名称为需要转成的类型,不可以有参数。前面不需要写返回类型,因为c++会自动返回函数名称这个类型。 转换函数通常后面有const,即不需要改变数据则要加const。

class Fraction
{
public:
    Fraction(int num,int den=1) : m_numerator(num),m_denominator(den){ }
    operator double() const{
        return (double)(m_numerator/m_denominator);
    }
private:
    int m_numerator;//分子
    int m_denominator;//分母
};

Fraction f(3,5);
double d = 4+f;//调用operator double() 将f转为0.6

# non-explicit-one-argument ctor

class Fraction
{
public:
    Fraction(int num,int den=1) : m_numerator(num),m_denominator(den){ }
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
    int m_numerator;//分子 
    int m_denominator;//分母
};

Fraction f(3,5);
Fraction d = f+4;//调用non-explicit ctor 将4转为Fraction(4,1),然后调用operator+
  • 这里没有写转换函数,而是重载了+操作符。
  • 重载之后的+是分数+分数,编译器处理d2 = f+4的时候,发现右边不是分数,则看4能否转换成分数。
  • 因为是只需要一个实参的构造函数,因此4可以转为分数,则可以调用重载之后的+。
  • 因此non-explicit-one-argument ctor可以把其他类型转换为该类型。

# conversion function VS. non-explicit-one-argument ctor

class Fraction
{
public:
    Fraction(int num,int den=1) : m_numerator(num),m_denominator(den){ }
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
    operator double() const{
        return (double)(m_numerator/m_denominator);
    }
private:
    int m_numerator;//分子 
    int m_denominator;//分母
};

Fraction f(3,5);
Fraction d = 4+f;//[Error] ambiguous

如果这两个并存了,编译器就不知道该调用哪个了。(不知道把分数转为double还是把int转为分数)

# explicit-one-argument ctor

class Fraction
{
public:
    explicit Fraction(int num,int den=1) : m_numerator(num),m_denominator(den){ }
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
    operator double() const{
        return (double)(m_numerator/m_denominator);
    }
private:
    int m_numerator;//分子 
    int m_denominator;//分母
};

Fraction f(3,5);
Fraction d = 4+f;//[Error] conversion from double to Fraction requested
  • 构造函数加上explicit之后,表示这个构造函数只能在构造的时候使用,不会在转换类型时使用了。
  • 这个explicit关键字主要就出现在这里。

# 模板

# 类模板

类模板用于实现类所需数据的类型参数化。 类模板在使用时,必须指定类型。

# 类模板派生普通类

子模板类派生时,需要具体化模板类,c++编译器要知道父类的数据类型具体是什么样的,因为 c++编译器要分配内存,必须知道父类所占内存大小
class SubClass : public MyClass<int>{};

# 类模板派生类模板

template class SubClass : public MyClass<T>

应该把类模板的声明和实现写在一起

# 类模板中的static关键字

  • 从类模板实例化的每一个模板类有自己的类模板数据成员,该模板的所有对象共享一个 static 数据成员
  • 和非模板类的 static 数据成员一样,模板类的 static 数据成员也应该在文件范围 定义和初始化
  • 每个模板类有自己类模板的 static 数据成员的副本

# 函数模板

  • 函数模板调用,将会严格匹配类型,不会进行自动类型转换;
  • 普通函数调用,可以进行隐式类型转换。
  • 编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

# 成员模板

# 例1

template<typename T1,typename T2>
struct pair{
    ...
    template<typename U1,typename U2>
    pair(const pair<U1,U2>& p):first(p.first),second(p.second){}
    ...    
};

pair<Base1,Base2> p(pair<Derived1,Derived2>());

# 例2

template<typeneme _Tp>
class shared_ptr:public __shared_ptr<_Tp>{
    ...
    template<typename _Tp1>
    explict shared_ptr(_Tp1* __p):__shared_ptr<_Tp>(__p){}
    ...
};

Base1* ptr = new Derived1; //up-cast
shared_ptr<Base1> sptr(new Derived1); //模拟up-cast

# 模板特化

template <class Key>
struct hash{};

template<>
struct hash<char>{};
template<>
struct hash<int>{};
template<>
struct hash<long>{};

# 模板偏特化

# 个数的偏

template <typename T, typename Alloc = ...>
class vector{};

template <typename Alloc = ...>
class vector<bool,Alloc>{};

# 范围的偏

template <typename T>
class C{};

template <typename T>
class C<T*>{};

# 模板模板参数

template<typename T,
            template<typename T>
            class Container
        >
class XCls{
private:
    Container<T> c;
public:
    ...
};

template<typename T>
using Lst = list<T,alloctor<T>>;
Xls<string,Lst> mylst1;
template<typename T,
            template<typename T>
            class SmartPtr
        >
class XCls{
private:
    SmartPtr<T> c;
public:
    XCls():sp(new T){}
};

Xls<string,shared_ptr> p1;
Xls<double,unique_ptr> p1; //错
Xls<int,weak_ptr> p1; //错
Xls<long,auto_ptr> p1;

# 数量不定的参数模板(varidic template)

void print(){
    ...
}

template<typename T,typename... Types>
void print(const T& firstArg,const Types&... args){
    cout << firstArg << endl;
    print(args...);
}

# 仿指针类 (pointer-like classes)

# 智能指针

template<typename T>
class shared_ptr{
public:
    T& operator*() const{
        return *px;
    }
    T* operator->() const{
        return px;
    }
private:
    T* px;
    long* pn;
}
//指向操作符具有传递作用
shared_ptr<Foo> sp(new Foo);
Foo f(*sp);
sp->method();
  • 设计的class,像指针。智能指针,完成比指针更多的工作。一般都是包着一层普通指针。
  • 指针允许的动作,这个类也需要允许操作。
  • *操作符和->操作符都需要重载。
  • 这样调用sp->的时候,实际上内部重载操作符,将内部的普通指针px返回出来,然后px可以继续使用->来完成。相当于这个->符号用了两次。 详讲:https://zhuanlan.zhihu.com/p/436290273

实践:https://blog.csdn.net/albertsh/article/details/82286999

# 迭代器

stl中的迭代器也是一种指针,迭代器这种智能指针不仅需要重载* ->操作符,还需要处理++,--等符号。

# 仿函数类 (function-like classes)

设计一个class,行为像一个函数,即仿函数。

template<class T>
struct identity{
    const T& operator()(const T& x) const{
        return x;
    }
}
  • 即可以使用小括号来调用。
  • 对小括号()操作符进行重载。
//一元函数对象 应用举例:for_each  
class print{
public:
    void operator()(const int& v){
        cout << v << " "; 
    }
};

for_each(v.begin(),v.end(), print());

//二元函数对象 应用举例:transform  
class myplus{
public:
    int operator()(int v1,int v2){
        return v1 + v2; 
    }
};

transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), myplus());

//一元谓词 应用举例:find_if  
class mygreater{
public:
    bool operator()(const int& v){
        return v > 2;
    }
};

vector<int>::iterator it = find_if(v.begin(), v.end(), mygreater()); //匿名函数对象
cout << *it << endl;

//二元谓词 应用举例:sort  
class mycompare{
public:
    bool operator()(int v1,int v2){
        return v1 > v2; 
    }
};

sort(v.begin(), v.end(), mycompare());

# 内建函数对象

使用内建函数对象,需要引入头文件 #include <functional>

6个算数类函数对象,除了 negate 是一元运算,其他都是二元运算。
    template<class T> T plus<T>//加法仿函数
    template<class T> T minute<T>//减法仿函数
    template<class T> T multiplies<T>//乘法仿函数
    template<class T> T divides<T>//除法仿函数
    template<class T> T modulus<T>//取模仿函数
    template<class T> T negate<T>//取反仿函数
6个关系运算类函数对象,每一种都是二元运算。
    template<class T> bool equal_to<T>//等于
    template<class T> bool not_equal_to<T>//不等于
    template<class T> bool greater<T>//大于
    template<class T> bool greater_equal<T>//大于等于
    template<class T> bool less<T>//小于
    template<class T> bool less_equal<T>//小于等于
3个逻辑运算类运算函数,not 为一元运算,其余为二元运算。
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
//使用内建函数对象声明一个对象
plus<int> myPlus;
cout << myPlus(5, 3) << endl;
//使用匿名临时对象
cout << plus<int>()(5, 6) << endl;

# 函数对象适配器

函数对象适配器是完成一些配接工作,这些配接包括绑定(bind),否定(negate),以及对一般函数或成员函数的修饰,使其成为函数对象

bind1st :将参数绑定为函数对象的第一个参数
bind2nd : 将参数绑定为函数对象的第二个参数
not1 : 对一元函数对象取反
not2 : 对二元函数对象取反
ptr_fun : 将普通函数修饰成函数对象
mem_fun : 修饰成员函数
mem_fun_ref : 修饰成员函数

如果希望函数对象适配器能对我们自己编写的函数对象有效,我们需要根据我们的函数对象类型继承 STL 的父类对象。

二元函数继承:public binary_function<参数类型,参数类型,返回类型> 一元函数继承:public unary_function<参数类型,返回类型>

//函数适配器 bind1st bind2nd
//现在我有这个需求 在遍历容器的时候,我希望将容器中的值全部加上 100 之后显示出来,怎么做
哇?
struct myprint : public binary_function<int,int,void>{ //二元函数对象 所以需要继承binary_fucntion<参数类型,参数类型,返回值类型>
void operator()(int v1 ,int v2) const{
cout << v1 + v2 << " "; }
};
//我们直接给函数对象绑定参数 编译阶段就会报错
//for_each(v.begin(), v.end(), bind2nd(myprint(),100));
//如果我们想使用绑定适配器,需要我们自己的函数对象继承 binary_function 或者unary_function
//根据我们函数对象是一元函数对象 还是二元函数对象
for_each(v.begin(), v.end(), bind2nd(myprint(), 100));

//总结: bind1st 和 bind2nd 区别?
//bind1st : 将参数绑定为函数对象的第一个参数
//bind2nd : 将参数绑定为函数对象的第二个参数
//bind1st bind2nd 将二元函数对象转为一元函数对象

vector<int>::iterator it = find_if(v.begin(), v.end(),
not1(bind2nd(less_equal<int>(), 2)));
cout << "it:" << *it << endl;
sort(v.begin(),v.end(),not2(greater<int>()));
for_each(v.begin(), v.end(), myprint02());
cout << endl;
//not1 对一元函数对象取反
//not2 对二元函数对象取反


//如何给一个普通函数使用绑定适配器(bind1st bind2nd)绑定一个参数?(拓展)
//ptr_fun
void myprint04(int v1,int v2){
cout << v1 + v2 << " "; }

//1 将普通函数适配成函数对象
//2 然后通过绑定器绑定参数
for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint04),100));
cout << endl;
//总结: ptr_fun 将普通函数转变为函数对象


//mem_fun mem_fun_ref
//如果我们容器中存储的是对象或者对象指针,如果能指定某个成员函数处理成员数据。
class student{
public:
    student(string name, int age) :name(name), age(age){}
    void print(){
        cout << "name:" << name << " age:" << age << endl;;
    }
    int age;
    string name;
};
void test05(){
//mem_fun : 如果存储的是对象指针,需要使用 mem_fun
vector<student*> v;
student* s1 = new student("zhaosi",10);
student* s2 = new student("liuneng", 20);
student* s3 = new student("shenyang", 30);
student* s4 = new student("xiaobao", 40);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
v.push_back(s4);
for_each(v.begin(), v.end(), mem_fun(&student::print));
cout << "-----------------------------" << endl;
//mem_fun_ref : 如果存储的是对象,需要使用 mem_fun_ref
vector<student> v2;
v2.push_back(student("zhaosi",50));
v2.push_back(student("liuneng", 60));
v2.push_back(student("shenyang", 70));
v2.push_back(student("xiaobao", 80));
for_each(v2.begin(), v2.end(), mem_fun_ref(&student::print));
编辑此页
#Generic Programming
算法
C++ Primer总结

← 算法 C++ Primer总结 →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式