代码之家  ›  专栏  ›  技术社区  ›  Sonny D

有没有办法只声明指向特定方法的指针?

  •  2
  • Sonny D  · 技术社区  · 8 年前

    我有一门课:

    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 不能声明只接受特定命名函数的。

    4 回复  |  直到 8 年前
        1
  •  3
  •   molbdnilo    8 年前

    你不能定义一个类型 是 &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);
    }
    

    .* 运算符不对其右操作数进行任何隐式转换。

    当然,这只是一种非常迂回和模糊的方式,简单地调用类型所指示的函数。

    如果一个类型可以保存一个预定的函数子集(比如, DoorOperation Opener 类型)。
    你也许可以用聪明的模板编程来构建它,但我不是一个聪明的模板程序员。

        2
  •  1
  •   Marek R    8 年前

    void (Car::*action)(int) 很少使用。 目前,有三种方法可供选择:

    • 模板参数(例如STL算法)
    • std::function<void()> 或是兰巴斯

    显然你需要第二个解决方案:

    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 .

        3
  •  1
  •   Peter - Reinstate Monica    8 年前

    马立克的正确建议,考虑使用更多的C++ -惯用的替代品,尽管如此,你的愿望是合理的,可以用简单的方法来实现。 const

    这样做的原因可能与所有其他常量定义(这些定义基本上都可以被其定义的右侧所取代)相同:希望有一个符号名称,以便特定值的含义在其使用上下文中可以理解,一个人想要有一个单一的维修点,以防他想要改变 常数

    const int s和 void (Car::*const action)(int) 他很像。

    所以,举一个人为的例子,如果你想要一个函数,它在每次汽车启动时都被调用,作为特定汽车的不可变属性,你可以声明一个 atStart 常量成员函数指针作为成员(我还引入了typedef)。指针必须在car的构造函数中初始化,因为所有const成员都必须初始化。

    #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)();
    };
    

    用户代码可以如下所示:

    int main()
    {
      cout << "I'll create a configured car. In which state do you live?\n";
    
      string state;
      cin >> state;
      Car *car = new Car(state == "Texas" ? &Car::turnOnAC : &Car::turnOnRadio);
    
      car->startEngine();
    
      delete car;
    }
    
        4
  •  1
  •   Evg    8 年前

    在评论中你说你问的是一个纯学术性的问题,所以让我给出一个纯学术性的答案。不能只指向一个方法的指针,因为所有这些方法都具有相同的类型。你能做的就是让他们有不同的类型:

    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的一条评论,他建议做基本上相同的事情。