静态成员函数与回调函数

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;
}

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

if (Point3d().get_object_count() > 1) {}

// (void) Point3d();
// if (Point3d::object_count > 1) {}
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;
}

回调函数和成员函数的关系在于:回调函数不能写成成员函数。如下的代码是无法编译执行的,同时第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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值