从explicit引出的仿函数的思考
以下为问题记录
问题: C++中explicit是什么,有什么用?
回答: 在C++中,explicit是用于修饰单个参数的构造函数,它的作用是防止隐式转换。如果一个构造函数被explicit修饰,那么编译器就会禁止隐式转换类型,只能通过显式类型转换来调用该构造函数。
explicit可以避免编译器在某些情况下自动调用拷贝构造函数或类型转换函数,从而避免了一些可能的类型转换错误,增加了代码的安全性和可读性。
例如:
class Test {
public:
explicit Test(int num) { m_num = num; }
private:
int m_num;
};
Test test = 5; // 编译错误
Test test(5); // 正确
Test test = Test(5); // 正确
在以上示例中,由于Test构造函数被explicit修饰,禁止了将int类型隐式转换为Test类型的操作,从而编译器会报错。需要显式调用Test构造函数才能创建Test对象。
问题: C++中的仿函数是什么,怎么使用?
回答: 在C++中,仿函数(Functor)是指实现了函数调用操作符operator()的类。通过重载operator(),我们可以将一个类的对象当作函数来使用。仿函数可以作为函数对象,可以像函数一样进行参数传递、返回值等操作,可以带有状态,实现一些函数无法实现的复杂操作。
使用仿函数可以在STL的算法中使用,例如sort、find_if、for_each等算法,都可以接受函数对象作为参数,方便进行各种操作。比如,我们可以写一个仿函数来实现自定义排序:
class SortByAge {
public:
bool operator() (const Person& p1, const Person& p2) const {
return p1.age < p2.age;
}
};
std::vector<Person> persons{{"Amy", 20}, {"Bob", 18}, {"Chris", 25}};
std::sort(persons.begin(), persons.end(), SortByAge());
// 对persons进行按年龄排序
上述代码中的sorbByAge
就是一个仿函数,它实现了operator()
, 返回值为bool
,并接受两个Person
对象作为参数,用于按照age
属性进行排序。
除了在STL算法中使用外,仿函数还可以用于原本需要函数指针的地方。比如,我们可以用仿函数来作为回调函数:
template <typename Callback>
void process(Callback callback) {
// 模拟某项处理操作
std::cout << "Processing..." << std::endl;
// 调用回调函数
callback();
// 模拟处理结束
std::cout << "Processed." << std::endl;
}
class CallbackFunction {
public:
void operator () () {
std::cout << "The process is done." << std::endl;
}
};
int main() {
CallbackFunction callback;
process(callback);
return 0;
}
上述代码中,我们定义了一个process
函数,需要传入一个回调函数,我们可以使用仿函数CallbackFunction
来作为回调函数。通过重载operator(),我们可以将该仿函数当作一个函数来使用,实现了更灵活的回调功能。
问题: 如果process函数内部没有调佣callback(),那么process(callback);这一句中callback是类对象还是函数?
回答: 在process
函数内部如果没有调用callback()
,那么callback
在process(callback);
这一句中就是一个函数对象,而不是一个函数。
回到process
函数的定义:
template <typename Callback>
void process(Callback callback) {
// ...
}
这里,process
函数以一个模板类型参数Callback
作为函数参数,该参数可以是任何类型。因此,在调用process(callback);
时,编译器不知道callback
具体是什么类型,只知道它是一个Callback
类型的实例。
如果process
函数内部没有调用callback()
,那么callback
就只是一个Callback
类型的实例,而不是一个函数。此时,如果我们尝试将其当做函数来调用callback();
,编译器会报错,因为callback
并不是一个函数类型。
因此,在使用仿函数时,需要确保在需要时将其当做函数来调用。如果一个函数只需要一个函数对象作为参数,而不会调用该函数对象的operator()
函数,那么我们不需要将其当做函数来使用。
记录一下,2023年6月25日23:34:22。