【CPP】函数重载、模版

1-Default Arguments

Default arguments

  • A feature in C++ (not C)
  • To call a function without providing one or more trailing arguments

default-argument.cpp

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

float norm(float x, float y, float z);
float norm(float x, float y, float z = 0);
float norm(float x, float y = 0, float z);

int main()
{
    cout << norm(3.0f) << endl;
    cout << norm(3.0f, 4.0f) << endl;
    cout << norm(3.0f, 4.0f, 5.0f) << endl;
    return 0;
}

float norm(float x, float y, float z)
{
    return sqrt(x * x + y * y + z * z);
}
cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

float norm(float x, float y, float z);
float norm(float x, float y = 0, float z);

int main()
{
    return 0;
}

float norm(float x, float y, float z)
{
    return sqrt(x * x + y * y + z * z);
}

缺失默认参数

默认参数要从尾部开始定义

重复定义默认参数也会报错:

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

float norm(float x, float y, float z);
float norm(float x, float y, float z = 0);
float norm(float x, float y = 0, float z = 4);

int main()
{
    return 0;
}

float norm(float x, float y, float z)
{
    return sqrt(x * x + y * y + z * z);
}

2-Function-Overloading

Why to overload?

  • C99
cpp 复制代码
<math.h>

double round (double x);
float roundf (float x);
long double roundl (long double x);
  • C++11
cpp 复制代码
<cmath>

double round (double x);
float round (float x);
long double round (long double x);
  • which one do you prefer?

Function overloading

  • Which function to choose? The compiler will perform name lookup
  • Argument-dependent lookup, also known as ADL
  • The return type will not be considered in name lookup
cpp 复制代码
#include <iostream>

using namespace std;

int sum(int x, int y)
{
    cout << "sum(int, int) is called" << endl;
    return x + y;
}
float sum(float x, float y)
{
    cout << "sum(float, float) is called" << endl;
    return x + y;
}
double sum(double x, double y)
{
    cout << "sum(double, double) is called" << endl;
    return x + y;
}

// //Is the following definition correct?
// double sum(int x, int y)
// {
//     cout << "sum(int, int) is called" << endl;
//     return x + y;
// }

int main()
{

    cout << "sum = " << sum(1, 2) << endl;
    cout << "sum = " << sum(1.1f, 2.2f) << endl;
    cout << "sum = " << sum(1.1, 2.2) << endl;

    //which function will be called?
    //cout << "sum = " << sum(1, 2.2) << endl;

    return 0;
}
cpp 复制代码
//Is the following definition correct?
double sum(int x, int y)
{
    cout << "sum(int, int) is called" << endl;
    return x + y;
}

两个函数如果只是返回值不同,是不可以被重载的

cpp 复制代码
#include <iostream>

using namespace std;

int sum(int x, int y)
{
    cout << "sum(int, int) is called" << endl;
    return x + y;
}
float sum(float x, float y)
{
    cout << "sum(float, float) is called" << endl;
    return x + y;
}
double sum(double x, double y)
{
    cout << "sum(double, double) is called" << endl;
    return x + y;
}
int main()
{

    //which function will be called?
    cout << "sum = " << sum(1, 2.2) << endl;

    return 0;
}

参数可以匹配多个函数,有歧义,报错

cpp 复制代码
#include <iostream>

using namespace std;

int sum(int x, int y)
{
    cout << "sum(int, int) is called" << endl;
    return x + y;
}

int main()
{

    //which function will be called?
    cout << "sum = " << sum(1, 2.2) << endl;

    return 0;
}
bash 复制代码
warning: implicit conversion from 'double' to 'int' changes value from 2.2 to 2 [-Wliteral-conversion]
    cout << "sum = " << sum(1, 2.2) << endl;
                        ~~~    ^~~
1 warning generated.

进行了隐式类型转换

3-Function Templates

Why function templates

  • The definitions of some overloaded functions may be similar

Explicit Instantiation

  • A function template is not a type, or a function, or any other entity
  • No code is generated from a source file that contains only template definitions
  • The template arguments must be determined, then the compiler can generate an actual function

实例化

cpp 复制代码
template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x +
     y;
}
// Explicitly instantiate
template double sum<double>(double, double);

// instantiates sum<char>(char, char), template argument deduced
template char sum<>(char, char);

// instantiates sum<int>(int, int), template argument deduced
template int sum(int, int);

template1.cpp

cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x +
     y;
}
// Explicitly instantiate
template double sum<double>(double, double);

int main()
{
    auto val = sum(4.1, 5.2);
    cout << val << endl;
    return 0;
}
bash 复制代码
The input type is d
9.3
cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x +
     y;
}
// Explicitly instantiate
template float sum<float>(float, float);

int main()
{
    auto val = sum(4.1, 5.2);
    cout << val << endl;
    return 0;
}
bash 复制代码
The input type is d
9.3

为什么还是调用了类型为double的函数?

为什么把函数删掉依然能够编译?

其实是因为函数可以做隐式实例化

Implicit Instantiation

  • Implicit instantiation occurs when a function template is not explicitly instantiated

隐式实例化

cpp 复制代码
template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x + y;
}
// Implicitly instantiates product<int>(int, int)
cout << "sum = " << sum<int>(2.2f, 3.0f) << endl;
// Implicitly instantiates product<float>(float, float)
cout << "sum = " << sum(2.2f, 3.0f) << endl;

template2.cpp

cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x + y;
}

int main()
{
    // Implicitly instantiates product<int>(int, int)
    cout << "sum = " << sum<int>(2.2f, 3.0f) << endl;
    // Implicitly instantiates product<float>(float, float)
    cout << "sum = " << sum(2.2f, 3.0f) << endl;

    return 0;
}
bash 复制代码
sum = The input type is i
5
sum = The input type is f
5.2

Function template specialization

  • We have a function template
cpp 复制代码
template<typename T> T sum(T x, T y)
  • If the input type is Point
cpp 复制代码
struct Point
{
  int x;
  int y;
};
  • But no + operator for Point;
  • We need to give a special definition for this case

specialization.cpp

cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x + y;
}

struct Point
{
    int x;
    int y;
};


int main()
{
    //Explicit instantiated functions
    cout << "sum = " << sum(1, 2) << endl;
    cout << "sum = " << sum(1.1, 2.2) << endl;

    Point pt1 {1, 2};
    Point pt2 {2, 3};
    Point pt = sum(pt1, pt2);
    cout << "pt = (" << pt.x << ", " << pt.y << ")" << endl;
    return 0;
}
bash 复制代码
specialization.cpp:9:14: error: invalid operands to binary expression ('Point' and 'Point')
    return x + y;
           ~ ^ ~
specialization.cpp:38:16: note: in instantiation of function template specialization 'sum<Point>' requested here
    Point pt = sum(pt1, pt2);

不合法的操作

专门去定义Point结构体模版

cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x + y;
}

struct Point
{
    int x;
    int y;
};

// Specialization for Point + Point operation
template<>
Point sum<Point>(Point pt1, Point pt2)
{
    cout << "The input type is " << typeid(pt1).name() << endl;
    Point pt;
    pt.x = pt1.x + pt2.x;
    pt.y = pt1.y + pt2.y;
    return pt;
}


int main()
{
    //Explicit instantiated functions
    cout << "sum = " << sum(1, 2) << endl;
    cout << "sum = " << sum(1.1, 2.2) << endl;

    Point pt1 {1, 2};
    Point pt2 {2, 3};
    Point pt = sum(pt1, pt2);
    cout << "pt = (" << pt.x << ", " << pt.y << ")" << endl;
    return 0;
}
bash 复制代码
sum = The input type is i
3
sum = The input type is d
3.3
The input type is 5Point
pt = (3, 5)

如果只是template 是实例化,如果加了template<> 是特例化。

4- Function Pointers and References

Function pointers

  • norm_ptr is a pointer, a function pointer
  • The function should have two float parameters, and returns float
cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

float norm_l1(float x, float y); //declaration
float norm_l2(float x, float y); //declaration
float (*norm_ptr)(float x, float y); //norm_ptr is a function pointer

int main()
{
    norm_ptr = norm_l1; //Pointer norm_ptr is pointing to norm_l1
    cout << "L1 norm of (-3, 4) = " << norm_ptr(-3.0f, 4.0f) << endl;

    norm_ptr = &norm_l2; //Pointer norm_ptr is pointing to norm_l2
    cout << "L2 norm of (-3, 4) = " << (*norm_ptr)(-3.0f, 4.0f) << endl;

    return 0;
}

float norm_l1(float x, float y)
{
    return fabs(x) + fabs(y);
}

float norm_l2(float x, float y)
{
    return sqrt(x * x + y * y);
}
bash 复制代码
L1 norm of (-3, 4) = 7
L2 norm of (-3, 4) = 5

函数指针:指向函数的指针,要求指向的函数要跟指针的类型完全相同,也就是说指针指向的函数应该要有两个参数,且这两个参数的类型都应该是float,返回值也是float

  • A function pointer can be an argument and pass to a function
cpp 复制代码
<stdlib.h>

void qsort(void *ptr, size_t count,  size_t size, int(*comp)(const void*, const void*));
  • To sort some customized types, such as
cpp 复制代码
struct Point
struct Person

Function references

function-reference.cpp

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

float norm_l1(float x, float y); //declaration
float norm_l2(float x, float y); //declaration
float (&norm_ref)(float x, float y) = norm_l1; //norm_ref is a function reference

int main()
{
    cout << "L1 norm of (-3, 4) = " << norm_ref(-3, 4) << endl;
    return 0;
}

float norm_l1(float x, float y)
{
    return fabs(x) + fabs(y);
}

float norm_l2(float x, float y)
{
    return sqrt(x * x + y * y);
}
bash 复制代码
L1 norm of (-3, 4) = 7

5- Recursive Functions

Recursive Functions

  • A simple example

recursion.cpp

cpp 复制代码
#include <iostream>
using namespace std;

void div2(double val);

int main()
{
    div2(1024.); // call the recursive function
    return 0;
}

void div2(double val)
{

    cout << "Entering val = " << val << endl;
    if (val > 1.0)
        div2( val / 2); // function calls itself
    else
        cout << "--------------------------" << endl;
    
    cout << "Leaving  val = " << val << endl;
}
bash 复制代码
Entering val = 1024
Entering val = 512
Entering val = 256
Entering val = 128
Entering val = 64
Entering val = 32
Entering val = 16
Entering val = 8
Entering val = 4
Entering val = 2
Entering val = 1
--------------------------
Leaving  val = 1
Leaving  val = 2
Leaving  val = 4
Leaving  val = 8
Leaving  val = 16
Leaving  val = 32
Leaving  val = 64
Leaving  val = 128
Leaving  val = 256
Leaving  val = 512
Leaving  val = 1024
  • Pros:
  1. Good at tree traversal
  2. Less lines of source code
  • Cons:
  1. Consume more stack memory
  2. May be slow
  3. Difficult to implement and debug
相关推荐
StrokeAce36 分钟前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
家有狸花4 小时前
VSCODE驯服日记(三):配置C++环境
c++·ide·vscode
dengqingrui1234 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝4 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O5 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
小飞猪Jay7 小时前
C++面试速通宝典——13
jvm·c++·面试
rjszcb8 小时前
一文说完c++全部基础知识,IO流(二)
c++
小字节,大梦想9 小时前
【C++】二叉搜索树
数据结构·c++
吾名招财9 小时前
yolov5-7.0模型DNN加载函数及参数详解(重要)
c++·人工智能·yolo·dnn
我是哈哈hh9 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝