18.手写一个function模板函数

手写一个function模板函数

实现需求:

使如下代码可以正常运行:

#include 

using namespace std;

int add(int a, int b) {
    return a + b;
}

class ADD_MULT {
public:
    ADD_MULT(int x) : x(x) {}
    int operator() (int a, int b) {
        return (a + b) * 2;
    }
    int x;
};

int main() {
    ADD_MULT add_mult(2);
    function f1 = add;
    function f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    f1 = f2;
    cout << f1(3, 4) << endl;
    f1 = add;
    f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    return 0;
}

实现:function模板样式:

template class function {};
template
class function {
public:
    
};

这里使用模板的偏特化,来实现需求

实现:构造函数(可以接收普通函数,也可以接收对象)

我们想要用同一个数据类型来同时接受两种不同的对象,这里就得使用**继承(接口)**来实现,

template
class BASE {
public:

};

template
class normal_function : public BASE {
public:

};

template
class B : public BASE {
public:

};

template class function {};
template
class function {
public:
    function(T (*ptr)(ARGS...)) : ptr(new normal_function(ptr)) {}
    template
    function(U &u) : ptr(new B(&u)) {}

private:
    BASE *ptr;
};

​ 这里我们可以使用BASE类来同时接受不同函数和对象。并且由于对象的类型是不确定的,所有我们得在类对象的构造函数上面加上模板,来处理这种情况。

普通函数的构造函数:

template
class normal_function : public BASE {
public:
    normal_function(T (*ptr)(ARGS...)) : ptr(ptr) {}

private:
    T (*ptr)(ARGS...);
};

​ 我们在这里定义一个函数指针,来接收我们函数地址,并进行初始话。

类对象的构造函数:

template
class B : public BASE {
public:
    B(U *u) : u(u), ptr(&U::operator()) {}

private:
    U *u;
    T (U::*ptr)(ARGS...);
};

​ 我们这里定义了一个指针对象,用来记录对象的地址,并定义了一个指向成员函数的指针(因为是虚函数,所有用虚函数表),来记录成员函数的地址。

​ 到这里我们就实现了如何同一个数据类型来同时接受两种不同的对象,也就是主函数中的这段代码:

	function f1 = add;
    function f2 = add_mult;

实现cout << f1(3, 4) << endl;

template
class BASE {
public:
    virtual T run(ARGS...) = 0;
};

template
class normal_function : public BASE {
public:
    normal_function(T (*ptr)(ARGS...)) : ptr(ptr) {}
    T run(ARGS... args) override {
        return ptr(forward(args)...);
    }

private:
    T (*ptr)(ARGS...);
};

template
class B : public BASE {
public:
    B(U *u) : u(u), ptr(&U::operator()) {}
    T run(ARGS... args) override {
        return (u->*ptr)(forward(args)...);
    }

private:
    U *u;
    T (U::*ptr)(ARGS...);
};

template class function {};
template
class function {
public:
    function(T (*ptr)(ARGS...)) : ptr(new normal_function(ptr)) {}
    template
    function(U &u) : ptr(new B(&u)) {}
    T operator()(ARGS... args) {
        return ptr->run(args...);
    }

private:
    BASE *ptr;
};

这里我们就可以用继承来实现各自的输出:

​ 代码中,BASE 类是一个纯虚基类,定义了一个 run 方法,但没有提供具体的实现。normal_functionB 类分别继承自 BASE,并提供了 run 方法的具体实现。

  • normal_function 类中,run 方法直接调用了存储的普通函数指针,并将传入的参数通过 forward 转发给该函数。
  • B 类中,run 方法通过类成员指针调用了存储的类成员函数指针,同样使用了 forward 转发参数。

​ 这样,通过继承自 BASE 并在派生类中实现 run 方法,你的 function 类就能够包装不同类型的函数指针了。

​ 在 function 类中,构造函数根据传入的参数类型选择相应的类来实例化,从而实现了对普通函数和类成员函数的封装。operator() 方法最终调用了 run 方法,使得你可以通过 function 对象调用包装的函数。

​ 需要注意的是,代码中使用了 forward(args)... 来转发参数,这是为了保留参数的完美转发性质,即传递参数时保留其值类别(lvalue 或 rvalue)和 const 限定符。

实现f1 = f2;赋值操作

template
class BASE {
public:
    virtual T run(ARGS...) = 0;
    virtual BASE *getCopy() = 0;
};

template
class normal_function : public BASE {
public:
    normal_function(T (*ptr)(ARGS...)) : ptr(ptr) {}
    T run(ARGS... args) override {
        return ptr(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new normal_function(ptr);
        return fun;
    }

private:
    T (*ptr)(ARGS...);
};

template
class B : public BASE {
public:
    B(U *u) : u(u), ptr(&U::operator()) {}
    T run(ARGS... args) override {
        return (u->*ptr)(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new B(u);
        return fun;
    }

private:
    U *u;
    T (U::*ptr)(ARGS...);
};

template class function {};
template
class function {
public:
    function(T (*ptr)(ARGS...)) : ptr(new normal_function(ptr)) {}
    template
    function(U &u) : ptr(new B(&u)) {}
    T operator()(ARGS... args) {
        return ptr->run(args...);
    }
    function &operator=(const function &fun) {
        delete ptr;
        this->ptr = fun.ptr->getCopy();
        return *this;
    }
    ~function() {
        delete ptr;
    }

private:
    BASE *ptr;
};
  • 赋值操作符首先删除当前对象 (this) 的 ptr 指针指向的对象

  • 然后通过调用 fun.ptr->getCopy() 来获取 fun 对象的一个副本,并将其赋值给当前对象的 ptr

  • 这里 getCopy 方法是一个虚函数,它在基类 BASE 中声明并在派生类中实现。在派生类中,getCopy 的实现会创建一个新的对象,该对象的类型是当前派生类,然后返回这个新对象的指针。

  • 赋值操作符实际上是在进行深拷贝,确保两个 function 对象之间不共享相同的函数对象。这里使用了虚函数 getCopy 来创建副本,而不是简单的指针复制。这可以防止在两个 function 对象中的 ptr 指针指向相同的内存位置,从而避免在一个对象的析构时影响另一个对象。

这是我们就基本完成了function模板函数的基本功能。

完整代码:

/*************************************************************************
        > File Name: test.cpp
        > Author:Xiao Yuheng
        > Mail:[email protected]
        > Created Time: Thu Nov 16 19:37:14 2023
 ************************************************************************/

#include 

using namespace std;

template
class BASE {
public:
    virtual T run(ARGS...) = 0;
    virtual BASE *getCopy() = 0;
};

template
class normal_function : public BASE {
public:
    normal_function(T (*ptr)(ARGS...)) : ptr(ptr) {}
    T run(ARGS... args) override {
        return ptr(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new normal_function(ptr);
        return fun;
    }

private:
    T (*ptr)(ARGS...);
};

template
class B : public BASE {
public:
    B(U *u) : u(u), ptr(&U::operator()) {}
    T run(ARGS... args) override {
        return (u->*ptr)(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new B(u);
        return fun;
    }

private:
    U *u;
    T (U::*ptr)(ARGS...);
};

template class function {};
template
class function {
public:
    function(T (*ptr)(ARGS...)) : ptr(new normal_function(ptr)) {}
    template
    function(U &u) : ptr(new B(&u)) {}
    T operator()(ARGS... args) {
        return ptr->run(args...);
    }
    function &operator=(const function &fun) {
        delete ptr;
        this->ptr = fun.ptr->getCopy();
        return *this;
    }
    ~function() {
        delete ptr;
    }

private:
    BASE *ptr;
};

int add(int a, int b) {
    return a + b;
}

class ADD_MULT {
public:
    ADD_MULT(int x) : x(x) {}
    int operator() (int a, int b) {
        return (a + b + x) * 2;
    }
    int x;
};

int main() {
    ADD_MULT add_mult(2);
    function f1 = add;
    function f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    f1 = f2;
    cout << f1(3, 4) << endl;
    f1 = add;
    f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    return 0;
}

优化:

/*************************************************************************
        > File Name: test.cpp
        > Author:Xiao Yuheng
        > Mail:[email protected]
        > Created Time: Thu Nov 16 19:37:14 2023
 ************************************************************************/

#include 
#include 

using namespace std;

int add(int a, int b) {
    return a + b;
}

class ADD_MULT {
public:
    ADD_MULT(int x) : x(x) {}
    int operator() (int a, int b) {
        return (a + b + x) * 2;
    }
    int x;
};

int main() {
    ADD_MULT add_mult(2);
    function f1 = add_mult;
    cout << f1(2, 3) << endl;
    add_mult.x = 10;
    cout << f1(2, 3) << endl;
    return 0;
}

我们在这里试着调用functional中的function模板函数,这里我们试着更改add_mult.x = 10;这个的值,然后再次输出:我们输出一下,看看结果:

在这里插入图片描述

可以发现值并没有发生变化,而我们用我们实现的代码来运行一下这段代码:

在这里插入图片描述

可以发现是会变化的,因为我们上面用的是指针来实现的,我们来进行修改(虽然我认为按照我的思路来说,修改了才是对的):

/*************************************************************************
        > File Name: test1.cpp
        > Author:Xiao Yuheng
        > Mail:[email protected]
        > Created Time: Thu Nov 16 20:02:50 2023
 ************************************************************************/

#include 

using namespace std;

template
class BASE {
public:
    virtual T run(ARGS...) = 0;
    virtual BASE *getCopy() = 0;
};

template
class normal_function : public BASE {
public:
    normal_function(T (*ptr)(ARGS...)) : ptr(ptr) {}
    T run(ARGS... args) override {
        return ptr(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new normal_function(ptr);
        return fun;
    }

private:
    T (*ptr)(ARGS...);
};

/*
template
class B : public BASE {
public:
    B(U *u) : u(u), ptr(&U::operator()) {}
    T run(ARGS... args) override {
        return (u->*ptr)(forward(args)...);
    }
    BASE *getCopy() override {
        BASE *fun = new B(u);
        return fun;
    }

private:
    U *u;
    T (U::*ptr)(ARGS...);
};
*/

template
class B : public BASE {
public:
    B(U u) : u(u) {}
    T run(ARGS... args) override {
        return u(forward(args)...);
    }
    BASE *getCopy() override {
        return new B(u);
    }

private:
    U u;
};

template class function {};
template
class function {
public:
    function(T (*ptr)(ARGS...)) : ptr(new normal_function(ptr)) {}
    template
    function(U &u) : ptr(new B(u)) {}
    T operator()(ARGS... args) {
        return ptr->run(args...);
    }
    function &operator=(const function &fun) {
        delete ptr;
        // this->ptr = fun.ptr;
        this->ptr = fun.ptr->getCopy();
        return *this;
    }
    ~function() {
        delete ptr;
    }

private:
    BASE *ptr;
};



int add(int a, int b) {
    return a + b;
}

class ADD_MULT {
public:
    ADD_MULT(int x) : x(x) {}
    int operator() (int a, int b) {
        return (a + b) * 2;
    }
    int x;
};

int main() {
    ADD_MULT add_mult(2);
    function f1 = add;
    function f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    f1 = f2;
    cout << f1(3, 4) << endl;
    f1 = add;
    f2 = add_mult;
    cout << f1(3, 4) << endl;
    cout << f2(3, 4) << endl;
    return 0;
}

​ 我们这里的B类的构造函数之间用一个B类的对象来继续接收就欧克了。

你可能感兴趣的:(c++,开发语言,c++)