2013-02-01 66 views
5

Có thể trong C++ không? Ví dụ tôi có một con trỏ tới một hàm mang theo không có tham số và kiểu trả về của nó là khoảng trống:Gán con trỏ cho một hàm địa chỉ của con trỏ tới đối tượng hàm

void (*f)(); 

và và một đối tượng hàm:

class A 
{ 
public: 
    void operator()() { cout << "functor\n"; } 
}; 

Có thể gán cho f địa chỉ đối tượng A? Và khi tôi gọi f() để gọi số A functor?

tôi đã cố gắng này, nhưng nó không hoạt động:

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    void operator()() { cout << "functorA\n"; } 
}; 

int main() 
{ 
    A ob; 
    ob(); 
    void (*f)(); 
    f = &ob; 
    f();  // Call ob(); 
    return 0; 
} 

tôi nhận được C:\Users\iuliuh\QtTests\functor_test\main.cpp:15: error: C2440: '=' : cannot convert from 'A *' to 'void (__cdecl *)(void)' There is no context in which this conversion is possible

Có cách nào để đạt được điều này?

+3

Bạn không thể sử dụng 'std :: function '? – chris

+0

Có cách nào để làm điều đó với tiêu chuẩn cũ, một trước khi C++ 11? –

Trả lời

5

Bạn không thể làm điều đó theo cách bạn đã chỉ định, bởi vì:

  1. toán tử() phải là hàm không tĩnh (yêu cầu tiêu chuẩn)
  2. con trỏ tới hàm không tĩnh phải có tham số ẩn - con trỏ đến cá thể lớp
  3. cuộc gọi của bạn đến f() không đưa ra bất kỳ dấu hiệu nào về trường hợp của đối tượng Một chức năng của bạn được gọi là

Sử dụng chức năng C++ 11 và std ::, như Stephane Rolland đã chỉ ra - bạn sẽ được quy định cụ thể các con trỏ đến các đối tượng trong các ràng buộc:

std::function<void(void)> f = std::bind(&A::operator(), &ob); 

(Xem question về việc sử dụng std :: chức năng trên các hàm thành viên)

+1

+1: cho std :: bind –

2

Có thể sử dụng tính năng C++ 1/C++ 0x, nhưng để đạt được điều này, bạn nên sử dụng hàm std :: có thể giải quyết hai loại, hàm và đối tượng.

#include <functional> 

class A 
{ 
public: 
    void operator()() { } 
}; 

int main() 
{ 
    std::function<void(void)> aFunction; 
    A ob; 

    aFunction = ob; 

// or as another user said 
// aFunction = std::bind(&A:operator(), &ob); 

    aFunction(); 

    void (*f)(); 

    aFunction = f; 

    aFunction(); 

    return 0; 
} 

và nếu bạn đang mắc kẹt với C++ 03, bạn có thể chơi với std::mem_funstd::ptr_fun

3

Nếu bạn sử dụng C++ 11, có thể sử dụng std::function

#include <functional> 

std::function<void()> f; 

int main() 
{ 
    A ob; 
    ob(); 

    f = ob; // f refers to ob 
    f();  // Call ob(); 
    return 0; 
} 
1

Làm thế nào về một số cách giải quyết như thế này:

Về cơ bản bạn muốn có một cách phổ biến gọi hàm thành viên và chức năng. Sau đó, có thể bạn có thể tạo một trình bao bọc sẽ đại diện cho một con trỏ chung cho một hàm hoặc hàm thành viên. Giả sử bạn có Base lớp và bạn muốn có thể gọi operator() của tất cả các lớp dẫn xuất.Sau đó, bạn cũng có một function() mà bạn muốn gọi cũng như:

class Base 
{ 
public: 
    virtual void operator()() = 0; 
}; 

class A : public Base 
{ 
public: 
    void operator()(){ std::cout << "A()" << std::endl; } 
}; 

void function() 
{ 
    std::cout << "function" << std::endl; 
} 

Nếu bạn tạo một wrapper cho phép bạn xây dựng con trỏ tùy chỉnh của bạn (MyFncPtr):

typedef void (Base::*BaseFncPtr)(); 
typedef void (*FncPtr)(); 

class MyFncPtr 
{ 
public: 
    MyFncPtr(FncPtr f) : fnc(f), baseObj(NULL), baseFnc(NULL) { } 
    MyFncPtr(BaseFncPtr fPtr, Base* objPtr) : baseFnc(fPtr), baseObj(objPtr), fnc(NULL) { } 
    void invoke() 
    { 
     if (baseObj && baseFnc) 
      (baseObj->*baseFnc)(); 
     else if (fnc) 
      fnc(); 
    } 

private: 
    BaseFncPtr baseFnc; 
    Base* baseObj; 
    FncPtr fnc; 
}; 

bạn có thể đạt được điều đó như này:

A a; 
MyFncPtr myPtr(&Base::operator(), &a); 
myPtr.invoke(); 
MyFncPtr myPtr2(function); 
myPtr2.invoke(); 

kết quả đầu ra:

A() 
function 

Hy vọng điều này sẽ giúp :)

+0

Chỉ cần lưu ý rằng nó khá là khái niệm giải pháp cuối cùng. Bạn nên xem xét vấn đề với các con trỏ lơ lửng khi bạn vẫn giữ đối tượng 'MyPtr' khi' baseObj' ban đầu bị hủy, vv. Con trỏ thông minh có thể được sử dụng để nó trở thành giải pháp thích hợp hơn :) – LihO

+0

+1 cho workaround hoạt động mà không có tính năng C++ 11 mới. Cảm ơn bạn! –

+0

@JohnSmith: Bạn được chào đón :) Vâng, tôi muốn chỉ ra rằng có những giải pháp khác so với những người dựa vào C++ 0x/C++ 11;) – LihO

Các vấn đề liên quan