Вызов методов класса C++ через указатель функции

Ужасно неэффективный путь, который мог бы работать, будет состоять в том, чтобы сохранить копию каждого пересечения в городе в течение каждой минуты дня. Маршрут шины от Elm St. и 2-й к Main St. и 25-й был бы представлен как, скажем,

elm_st_and_2nd[12][30].edges :
 elm_st_and_1st[12][35] # 5 minute walk to the next intersection
   time = 5 minutes
   transport = foot
 main_st_and_25th[1][15] # 40 minute bus ride
   time = 40 minutes
   transport = bus
 elm_st_and_1st[12][36] # stay in one place for one minute
   time = 1 minute
   transport = stand still

Выполнение Ваш любимый новаторский алгоритм на этом графике и молился бы о хорошей реализации виртуальной памяти.

104
задан Jon Seigel 16 April 2010 в 20:24
поделиться

7 ответов

Прочтите этот для получения подробной информации:

// 1 define a function pointer and initialize to NULL

int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;

// C++

class TMyClass
{
public:
   int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
   int DoMore(float a, char b, char c) const
         { cout << "TMyClass::DoMore" << endl; return a-b+c; };

   /* more of TMyClass */
};
pt2ConstMember = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore

// Calling Function using Function Pointer

(*this.*pt2ConstMember)(12, 'a', 'b');
114
ответ дан 24 November 2019 в 04:07
поделиться

Как получить указатель на функцию для функции-члена класса, а затем вызвать этот член функция с конкретным объектом?

Проще всего начать с typedef . Для функции-члена вы добавляете имя класса в объявление типа:

typedef void(Dog::*BarkFunction)(void);

Затем, чтобы вызвать метод, вы используете оператор -> * :

(pDog->*pBark)();

Кроме того, если возможно, я хотел бы вызвать конструктор также через указатель. Возможно ли это, и если да, то каков предпочтительный способ сделать это?

Я не верю, что вы можете работать с такими конструкторами - ctors и dtors особенные. Обычный способ добиться такого рода вещей - использовать фабричный метод, который в основном представляет собой статическую функцию, вызывающую за вас конструктор. См. Пример в приведенном ниже коде.

Я изменил ваш код, чтобы в основном делать то, что вы описываете. Ниже приведены некоторые предостережения.

#include <iostream>

class Animal
{
public:

    typedef Animal*(*NewAnimalFunction)(void);

    virtual void makeNoise()
    {
        std::cout << "M00f!" << std::endl;
    }
};

class Dog : public Animal
{
public:

    typedef void(Dog::*BarkFunction)(void);

    typedef Dog*(*NewDogFunction)(void);

    Dog () {}

    static Dog* newDog()
    {
        return new Dog;
    }

    virtual void makeNoise ()
    {
        std::cout << "Woof!" << std::endl;
    }
};

int main(int argc, char* argv[])
{
    // Call member function via method pointer
    Dog* pDog = new Dog ();
    Dog::BarkFunction pBark = &Dog::makeNoise;

    (pDog->*pBark)();

    // Construct instance via factory method
    Dog::NewDogFunction pNew = &Dog::newDog;

    Animal* pAnimal = (*pNew)();

    pAnimal->makeNoise();

    return 0;
}

Теперь, хотя вы обычно можете использовать Dog * вместо Animal * благодаря магии полиморфизма, тип указателя на функцию делает не следуют правилам поиска иерархии классов. Таким образом, указатель на метод Animal несовместим с указателем на метод Dog, другими словами, вы не можете назначить Dog * (*) () переменной типа Animal * (*) ( ) .

Статический метод newDog представляет собой простой пример фабрики, которая просто создает и возвращает новые экземпляры. Будучи статической функцией, она имеет обычный typedef (без квалификатора класса).

Ответив на вышеупомянутый вопрос, мне интересно, есть ли ' Не лучший способ достичь того, что вам нужно. Есть несколько конкретных сценариев, в которых вы бы поступили подобным образом, но вы можете обнаружить, что есть другие шаблоны, которые лучше подходят для вашей проблемы. Если вы опишете в более общих выражениях, чего пытаетесь достичь, коллективный разум может оказаться еще более полезным!

В связи с вышесказанным вы, несомненно, найдете библиотеку Boost bind и другие связанные модули очень полезны.

55
ответ дан 24 November 2019 в 04:07
поделиться

Причина, по которой нельзя использовать указатели функций для вызова функций-членов, заключается в том, что обычные указатели на функции обычно являются просто адресом памяти функции.

Чтобы вызвать функцию-член, вам нужно знать две вещи:

  • Какую функцию-член вызывать
  • Какой экземпляр следует использовать (чья функция-член)

Обычные указатели на функции не могут хранить и то, и другое. Указатели на функции-члены C ++ используются для хранения a), поэтому вам нужно явно указать экземпляр при вызове указателя функции-члена.

6
ответ дан 24 November 2019 в 04:07
поделиться

Указатель функции на член класса - это проблема, которая действительно подходит для использования boost :: function. Небольшой пример:

#include <boost/function.hpp>
#include <iostream>

class Dog 
{
public:
   Dog (int i) : tmp(i) {}
   void bark ()
   {
      std::cout << "woof: " << tmp << std::endl;
   }
private:
   int tmp;
};



int main()
{
   Dog* pDog1 = new Dog (1);
   Dog* pDog2 = new Dog (2);

   //BarkFunction pBark = &Dog::bark;
   boost::function<void (Dog*)> f1 = &Dog::bark;

   f1(pDog1);
   f1(pDog2);
}
6
ответ дан 24 November 2019 в 04:07
поделиться

Обратите внимание, что, начиная с Java 6, скриптовый API встроен в стандартную библиотеку Java, и вам действительно больше не нужна сторонняя библиотека, такая как Mozilla Rhino. (Фактически, API сценариев в Java 6 является адаптированной версией Mozilla Rhino.)

См. документацию API для пакета javax.script и см .: Сценарии для платформы Java .

Версия Java по умолчанию в Mac OS X 10.6 (Snow Leopard) - Java 6, поэтому вы должны иметь возможность использовать стандартный API сценариев без установки чего-либо особенного.

Примечание. : Я обнаружил, что jrunscript установлен на моем Mac, но по какой-то причине его нет в PATH, поэтому он не может найти его, если я наберу jrunscript в терминале. В моей файловой системе это здесь:

18
ответ дан 24 November 2019 в 04:07
поделиться

I не думаю, что кто-то объяснил здесь, что одна проблема заключается в том, что вам нужны « указатели на элементы », а не обычные указатели на функции.

Указатели на элементы для функций - это не просто указатели на функции. С точки зрения реализации, компилятор не может использовать простой адрес функции, потому что, как правило, вы не знаете адрес для вызова, пока не узнаете, какой объект разыменовать (подумайте о виртуальных функциях). Вы также должны знать объект, чтобы, конечно, предоставить неявный параметр this .

Сказав, что они вам нужны, теперь я скажу, что вам действительно нужно их избегать. Серьезно, указатели на члены - это боль. Гораздо разумнее взглянуть на объектно-ориентированные шаблоны проектирования, которые достигают той же цели, или использовать boost :: function или что-то еще, как упомянуто выше - при условии, что вы можете сделать этот выбор, то есть.

Если вы поставляете этот указатель на функцию в существующий код, поэтому вам действительно нужен простой указатель на функцию, вам следует написать функцию как статический член класса. Статическая функция-член не понимает this , поэтому вам нужно передать объект в качестве явного параметра. Когда-то в этих строках существовала не такая уж необычная идиома для работы со старым кодом C, которому нужны указатели функций

class myclass
{
  public:
    virtual void myrealmethod () = 0;

    static void myfunction (myclass *p);
}

void myclass::myfunction (myclass *p)
{
  p->myrealmethod ();
}

Поскольку myfunction на самом деле просто обычная функция (не считая проблем с областью видимости), указатель функции может можно найти обычным способом C.

EDIT - этот вид метода называется «методом класса» или «статической функцией-членом». Основное отличие от функции, не являющейся членом, состоит в том, что если вы ссылаетесь на нее извне класса, вы должны указать область с помощью оператора разрешения области :: . Например, чтобы получить указатель на функцию, используйте & myclass :: myfunction , а для его вызова используйте myclass :: myfunction (arg); .

Подобные вещи довольно распространены. при использовании старых API Win32, которые изначально были разработаны для C, а не C ++.

31
ответ дан 24 November 2019 в 04:07
поделиться

Чтобы создать новый объект, вы можете либо использовать новое размещение, как упомянуто выше, либо реализовать в вашем классе метод clone (), который создает копию объекта. Затем вы можете вызвать этот метод клонирования с помощью указателя на функцию-член, как описано выше, для создания новых экземпляров объекта. Преимущество клонирования состоит в том, что иногда вы можете работать с указателем на базовый класс, когда вы не знаете тип объекта. В этом случае проще использовать метод clone (). Кроме того, clone () позволит вам скопировать состояние объекта, если вы этого хотите.

2
ответ дан 24 November 2019 в 04:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: