2016-05-04 8 views
1
class foo{ 
    public: 
    int n; 
    private: 
    virtual void sayHi(){ 
     cout<<"Hi there!"; 
    } 

}; 

Как получить адрес sayHi() ??Доступ к личной виртуальной функции-члену через указатели

main(){ 
foo f; 
typedef void(*fptr)(); 
fptr func = reinterpret_cast<fptr>((&f)[0]); 
(*func)(); 
} 

Код выше не работает.

Я знаю, что первые 8 байтов объекта «f» являются указателем на виртуальную таблицу, в которой содержатся указатели на функции, я использую 64-разрядную машину. Я в основном пытаюсь вызвать sayHi() через свой указатель, а не называть его непосредственно из f, так как sayHi() является приватным в любом случае! Как мне это сделать? Я распределяю его правильно?

+0

мы говорим о стандартном C++ , или C++ на ваших спецификациях c компилятор, операционная система и архитектура процессора? – immibis

+0

Я использую 64-битную машину. Но это нормально со стандартным C++. Благодаря! –

+3

@Noor Thabit: Er ... Ничего подобного не может быть сделано в «стандартном C++». Стандартный C++ даже не имеет понятия «виртуальная таблица». – AnT

ответ

0

Ну, ISO C++ запрещает принимать адрес связанной функции-члена, чтобы сформировать указатель на функцию-член. Однако вы можете сделать что-то подобное, если это поможет. Вы можете проверить результат here.

#include <iostream> 
using namespace std; 

class foo{ 
    int n; 
public: 
    virtual void sayHi(){ 
     cout<<"Hi there!"; 
    } 
}; 

typedef void(*fptr)(); 

int main() { 
    auto func = reinterpret_cast<fptr>(&foo::sayHi); 
    (*func)(); 
    return 0; 
} 
+1

Это не переносимый код и вряд ли будет работать во время выполнения. Вы назначаете указатель на метод необработанному указателю, используя тип-cast, чтобы компилятор не жаловался на что-то потенциально незаконное и опасное. И вы по-прежнему не можете * вызывать * метод нестатического класса с использованием необработанного указателя, стек вызовов не будет настроен правильно. –

+0

Спасибо за комментарий! Ваше решение работает! Однако функция должна быть закрытой! –

2

Вы не можете просто иметь указатель на нестационарную функцию-член и вызывать ее без объекта. Самый прямой способ интерпретировать ваш вопрос будет с помощью pointer-to-member как в:

auto fptr = &foo::sayHi; 
foo f; 
(f.*fptr)(); 

Теперь вы говорите, что вы хотите назвать это без того, чтобы пройти через f. Не совсем ясно, что это значит. Использование лямбда, вероятно, достаточно хорошо, чтобы создать отзывной, который работает, как вы хотите

auto func = [] { return foo{}.sayHi(); }; 
func(); // call 

или с использованием конкретного объекта и захватив его по ссылке (как показано) или по значению

foo f; 
auto func = [&f] { return f.sayHi(); }; 
func(); 
+1

Спасибо за ответ! Но это не сработало. –

+0

@NoorThabit: Почему бы и нет? –

+0

Может быть, потому что 'sayHi' является приватным! @MooingDuck –

1

sayHi() не является статический метод класса. Вам нужно использовать указатель вместо необработанного указателя (реализация указателя метода является специфичной для компилятора, поэтому предполагать, что внутренняя компоновка указателя на метод не переносима).

Кроме того, sayHi() является частным к foo, так main() не может получить доступ к нему напрямую. Вам нужно либо:

  1. объявить sayHi(), как общественного:

    class foo 
    { 
        int n; 
    public: 
        virtual void sayHi(){ 
         cout << "Hi there!"; 
        } 
    }; 
    
    int main() 
    { 
        typedef void (foo::*fptr)(); 
        fptr func = &foo::sayHi; 
        foo f; 
        (f.*func)(); 
        return 0; 
    } 
    
  2. сделать main() быть friend из foo:

    class foo 
    { 
        int n; 
        virtual void sayHi(){ 
         cout << "Hi there!"; 
        } 
        friend int main(); 
    }; 
    
    int main() 
    { 
        typedef void (foo::*fptr)(); 
        fptr func = &foo::sayHi; 
        foo f; 
        (f.*func)(); 
        return 0; 
    } 
    
+0

Спасибо за внимание. Но sayHi() является приватным! –

+0

@Remy Код не компилируется! –

+0

@EissaN: код компилируется для меня, при условии, что 'sayHi()' объявлен как 'public', или если' main() 'объявлен как' friend' 'foo', в противном случае' main() 'не может получить к нему доступ. –