我有一堂课
class Car
{
public:
Car();
~Car();
// nr indicates which particular door.
void startEngie();
void openDoor(int nr);
void closeDoor(int nr);
void openWindow(int nr);
void closeWindow(int nr);
void turnOnAirConditioner(int vloume);
}
现在,void (Car::*action)(int)
声明了一个指向action
方法的名为Car
的指针。问题在于可以为它分配许多方法:&Car::openDoor
,&Car::closeDoor
,&Car::openWindow
,&Car::closeWindow
,&Car::turnOnAirConditioner
,但不能分配&Car::startEngie
。
我想知道我是否正确:没有办法只声明一个指向特定方法的指针。换句话说:pointer type
仅接受特定的命名函数,无法声明。
答案 0 :(得分:3)
您不能定义 只是“另一种类型的一个特定值”的类型,例如,仅存在的值恰好是&Car::closeDoor
的类型。
您可以做的一件事是接触瑞士军刀编程-引入一个间接级别-并定义一个表示 的特定值的类型,方法是将其包装起来里面的东西。
// Simplified Car
class Car
{
public:
void openDoor(int i) { std::cout << "open door\n"; }
void closeWindow(int i) { std:cout << "close window\n"; }
};
using Fun = void (Car::*)(int);
// A template for an immutable structure, so it
// can hold only one specific value; the template argument.
template<Fun fun>
struct CarOperation
{
const Fun f = fun;
};
// Now we can make one type for each operation
using OpenDoor = CarOperation<&Car::openDoor>;
using CloseWindow = CarOperation<&Car::closeWindow>;
int main()
{
Car c;
OpenDoor d;
(c.*d.f)(1);
CloseWindow e;
(c.*e.f)(2);
}
语法有点不幸,因为显然.*
运算符不会对其右操作数进行任何隐式转换。
当然,这只是简单地调用类型所指示的函数的一种round回和混淆的方式。
对于可以容纳函数的预定子集的类型(例如DoorOperation
或Opener
类型),这将更为有用。
您可能可以使用聪明的模板编程来构建它,但是我不是一个聪明的模板程序员。
答案 1 :(得分:1)
这种指针void (Car::*action)(int)
很少使用。
如今,有三种首选的方法可以解决此问题:
std::function<void()>
和或lambdas 显然您需要第二种解决方案:
class IWindowOpenable {
public:
virtual ~IWindowOpenable() {}
virtual void openWindow(int nr) = 0;
};
class Car : public IWindowOpenable
{
public:
Car();
~Car();
void startEngie();
void openDoor(int nr);
void closeDoor(int nr);
void openWindow(int nr);
void closeWindow(int nr);
void turnOnAirConditioner(int vloume);
};
Car car;
IWindowOpenable *windowOpener = &Car;
请注意,实现接口IWindowOpenable
的所有内容只能在名称为openWindow
的方法上运行。
该指针可以指向实现此接口的对象的任何错字。
答案 2 :(得分:1)
在评论中,您说您是在问一个纯粹的学术问题,所以让我给出一个纯粹的学术答案。您不能仅指向一个方法,因为所有这些方法都具有相同的类型。您可以做的是使它们具有不同的类型:
struct Car
{
struct open_door_tag { };
struct close_door_tag { };
void open_left_door(int nr, open_door_tag = {});
void open_right_door(int nr, open_door_tag = {});
void close_door(int nr, close_door_tag = {});
};
现在,如果您有指针
void (Car::*open_that_door_ptr)(int, Car::open_door_tag);
您对分配有一些限制:
open_that_door_ptr = &Car::open_left_door; // OK
open_that_door_ptr = &Car::open_right_door; // OK
//open_that_door_ptr = &Car::close_door; // Won't compile
不幸的是(或没有),您不能在没有提供标签的情况下通过此指针调用方法:
Car car;
(car.*open_that_door_ptr)(2, Car::open_door_tag{});
// or (thanks, @Jarod42)
(car.*open_that_door_ptr)(2, {});
// (car.*open_that_door_ptr)(2); // Won't compile
注意。在我发布此答案后,我看到@ Jarod42的评论,他建议做基本上相同的事情。
答案 3 :(得分:1)
Marek给出了考虑使用更多C ++惯用替代方法的正确建议,尽管您的希望是合理的,并且可以通过简单的bundle install
来实现。
可能要这样做的原因与所有其他const定义相同(原则上所有这些都可以用其定义的右侧代替):一个人想要一个符号名称,以便特定的含义值在使用中是可以理解的,并且如果希望更改const
值,则需要一个维护点。这就是为什么每个人都不喜欢代码中的整数文字。
这些确切原因适用于const
和const int
的定义。
因此,举一个人为的例子,如果您想在每次汽车启动时都调用一个函数,作为该特定汽车的非可变属性,则可以声明一个void (Car::*const action)(int)
常量成员函数指针作为成员(我也介绍了typedef)。指针必须在汽车的构造函数中初始化,就像所有const成员一样。
atStart
用户代码如下:
#include<iostream>
using namespace std;
struct Car
{
typedef void (Car::* const CarfuncT)(void);
Car(CarfuncT atStartArg)
: atStart(atStartArg)
{}
void startEngine() { cout << "Start Engine\n"; (this->*atStart)(); };
void turnOnAC() { cout << "AC on\n"; }
void turnOnHeat() { cout << "Heat on\n"; }
void turnOnRadio() { cout << "Radio on\n"; }
void (Car::* const atStart)();
};