2017-12-26 166 views
6

Tôi cần gọi phương thức cơ sở A :: foo() từ lớp dẫn xuất bằng con trỏ.Gọi cơ sở phương thức ảo bằng con trỏ tới hàm từ lớp dẫn xuất

#include <iostream> 
struct A{ 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
}; 

struct B:A{ 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void callBase(void (A::*f)()){ 
     (this->*f)(); 
    } 
}; 

int main(){ 
    B* p=new B(); 
    p->callBase(&A::foo); 
} 

Đầu ra mã này "B :: foo". Có thể gọi A :: foo() bằng con trỏ tới phương thức không?

+0

Tôi không nghĩ rằng bạn có thể. Tuy nhiên, tôi đã sai trong quá khứ :) Hãy hy vọng một người hiểu biết nhiều hơn tôi biết một cách. –

+1

Bạn có thể gọi nó trực tiếp như 'p-> A :: foo();' nhưng không thông qua con trỏ tới hàm thành viên (mà tôi đoán là điểm của các hàm ảo). –

+0

Tôi tin rằng bạn làm việc xung quanh điều này bằng cách có một 'bar' không ảo thực hiện công việc và có' foo' delegate tới 'bar',' callBase' sau đó gọi 'bar'. Điều này là hợp lý hơn vì đa hình có nghĩa là 'B' nên luôn luôn gọi riêng' foo' –

Trả lời

1

Vâng, bạn có thể làm điều gì đó tương tự bằng cách sử dụng một số thủ thuật với ghi đè giá trị this. Bạn có lẽ không bao giờ nên cố gắng làm điều đó mặc dù, vtable con trỏ không có nghĩa là phải được sửa đổi bằng tay.

Để làm những gì bạn mô tả, chúng tôi cần phải có con trỏ đến A vtable. Đối tượng của chúng tôi p chỉ trỏ đến số vtable của B, vì vậy chúng tôi cần lưu trữ con trỏ thứ hai trong một trường trong hàm tạo của A.

Đây là mã:

#include <iostream> 
struct A{ 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
    int *a_vtable_ptr; 
    // First, save value of A's vtable pointer in a separate variable. 
    A() { a_vtable_ptr = *(int**)this; } 
}; 

struct B:A{ 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void callBase(void (A::*f)()){ 
     int *my_vtable_ptr = *(int**)this; 
     // Then modify vtable pointer of given object to one that corresponds to class A. 
     *(int**)this = a_vtable_ptr; 
     (this->*f)(); // Call the method as usual. 
     // Restore the original vtable pointer. 
     *(int**)this = my_vtable_ptr; 
    } 
}; 

// Function main() is not modified. 
int main(){ 
    B* p=new B(); 
    void (A::*f)() = &A::foo; 
    p->callBase(f); 
} 

Output:

A::foo() 

Process finished with exit code 0 
1

phương pháp ảo được thiết kế để thực hiện đa hình và con trỏ đến các phương pháp ảo hỗ trợ hành vi đa hình của họ. Nhưng bạn cho khả năng gọi phương thức cơ bản bằng cách gọi một cách rõ ràng p->A::foo().

Vì vậy, nếu bạn muốn gọi phương thức cơ sở bằng con trỏ, bạn nên làm cho nó không ảo (như @PasserBy được đề cập trong các nhận xét).

Mã dụ:

struct A { 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
    void bar() { std::cout << "A::bar()" << std::endl; } 
    void callBase(void (A::*f)()) { (this->*f)(); } 
}; 

struct B : A { 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void bar() { std::cout << "B::bar()" << std::endl; } 
}; 

int main() 
{ 
    A* p = new B(); 
    p->foo(); 
    p->bar(); 
    p->callBase(&A::foo); 
    p->callBase(&A::bar); 
    p->A::foo(); 
    p->A::bar(); 
} 

Output:

B::foo() 
A::bar() 
B::foo() 
A::bar() 
A::foo() 
A::bar() 
Các vấn đề liên quan