• 静态成员函数与回调函数


    1. 静态成员函数

    1.1 静态成员函数调用

    如何代码块里的函数get_object_count是静态成员函数,对静态成员函数无论是通过类名还是通过对象或对象指针调用,最终都会被编译器转换为全局非成员函数的调用。例如obj.get_object_count()或Point3d::get_object_count()都会被编译器通过名称处理后转化为_ZN7Point3d16get_object_countEv()。
    在c++没有提供静态函数成员时,或想调用类里的一个函数,且此函数并没有使用类的任何数据成员,类似下面第9行的函数num_test,则可以使用((Point3d *) nullptr)->num_test()这样的方式,注意这种方式是将空指针作为this指针传递进成员函数内,所以在这个函数内是不能够访问数据成员的,否则通过空指针调用会引发异常。
    因此可以发现,若一个成员函数没有使用任何类非静态函数成员与非静态数据成员,那么这个成员函数是不需要this指针的,因此也就没必要通过一个类对象来调用,所以当然应该把这个成员函数设置为静态的。

    class Point3d {
    public:
        static int object_count;
    
        static int get_object_count() {
            return object_count;
        }
    
        int num_test() {
            return object_count;
        }
    
    private:
        double x{}, y{}, z{};
    };
    
    int Point3d::object_count = 10;
    
    double Point3d::magnitude() const { return sqrt(x * x + y * y + z * z); }
    
    double magnitude(const Point3d *ptr);
    
    int main() {
        std::cout << Point3d::get_object_count() << std::endl;
        printf("%p\n", &Point3d::get_object_count);
        std::cout<<((Point3d *) nullptr)->num_test();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    当然即使采用对象调用静态成员函数,经过编译器的处理最终也是调用一个全局函数,是不会给这个函数传递this指针的。如下所示的第一行的通过类对象调用的方法会在编译器内部转换为3-4行的调用方式,注意虽然这个匿名对象在第4行是没有用的,但是仍然需要生成,因为这个生成有可能会改变程序执行,所以不能直接省略。

    if (Point3d().get_object_count() > 1) {}
    
    // (void) Point3d();
    // if (Point3d::object_count > 1) {}
    
    • 1
    • 2
    • 3
    • 4
    1.2 回调函数

    回调函数的讲解可以参考,其作用在于对函数的解耦和复用。例如如下的代码就是一个回调函数的例子,调用sort函数的主函数可以被称为起始函数,bubble_sort函数是中间函数,less函数是回调函数。这里只需要一个中间函数就可以实现不同规则的排序,即可以从小到大或从大到小,只需要改变回调函数即可。

    using Compare = bool (*)(int, int);
    
    void bubble_sort(std::vector<int> &vec, Compare compare) {
        //冒泡排序
        for (auto i = 0; i < vec.size(); ++i) {
            for (auto j = 1; j < vec.size() - i; ++j) {
                if (compare(vec[j - 1], vec[j])) {
                    std::swap(vec[j - 1], vec[j]);
                }
            }
        }
    }
    
    bool less(int i, int j) {
        return i > j;
    }
    
    int main() {
        std::vector<int> vec{2, 4, 1, 6, 5};
        bubble_sort(vec, less);
        std::for_each(vec.begin(), vec.end(), [](int i) { std::cout << i << " "; });
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    回调函数和成员函数的关系在于:回调函数不能写成成员函数。如下的代码是无法编译执行的,同时第10-11行也是无法执行的,它们的逻辑是一致的:不能通过函数地址直接调用类非静态成员函数,因为这种函数隐含了一个this指针,如果不通过类对象去调用,是无法传递this指针的,会出现缺少参数的错误。
    第二种错误理解角度是函数类型不一致,如下编译器报错,也就是说类成员函数testB的实际类型是void(Point3d:: *)(),而传递的函数指针类型为void (*)(),类型不一致,所以无法编译通过,而这个解决办法即是将testB改为static类型,而static的函数类型为void (*)()。

    Alt

    using CallFunc=void (*)();
    
    class backCall {
    
    
    public:
        void testA(CallFunc callFunc) {
            cout << 1 << endl;
            callFuc();
            // auto f=&backCall::testB;
            // f();
        }
    
        void testB() {
            cout << 2 << endl;
        }
    };
    
    
    int main() {
        backCall().testA(&backCall::testA);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    Centos 7 部署Docker CE和docker-compose教程
    嵌入式-C语言逻辑运算符
    2023常州大学计算机考研信息汇总
    关于Python爬虫兼职,这里有一条高效路径
    51单片机+DS1302设计一个电子钟(LCD1602显示时间)
    机器学习项目:客户分群——K-Means 聚类从选参到业务画像的完整实战
    DQL命令查询数据(二)
    网络资源模板--基于 Android Studio 实现的天气预报App
    裁剪图片vue-cropper实例 基础功能 预览 获取裁剪后图片数据
    阶段性总结 | C语言
  • 原文地址:https://blog.csdn.net/baidu_41922918/article/details/127943160