Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.78
atomohod
20 / 20 / 1
Регистрация: 01.04.2010
Сообщений: 57
#1

CALLBACK. Нужна помощь - C++

06.11.2011, 21:52. Просмотров 1174. Ответов 28
Метки нет (Все метки)

Всем привет!

Есть такой код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ExpressionCalculator
{
private:
    double(ExpressionCalculator::*fn)(double,double,double,double);
public:
    ExpressionCalculator(void);
    ~ExpressionCalculator(void);
 
    double f1(double a, double b, double c, double d);
    double f2(double a, double b, double c, double d);
    double f3(double a, double b, double c, double d);
 
    double Calculate(double a, double b, double c, double d);
 
};
в *.cpp пробую:
C++
1
2
3
4
5
double ExpressionCalculator::Calculate(double a, double b, double c, double d)
{
    double tmp = fn(a,b,c,d);
    return tmp;
}
на
C++
1
double tmp = fn(a,b,c,d);
получаю при компиляции

error C2064: результатом вычисления фрагмента не является функция, принимающая 4 аргументов

подскажите, что не так?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.11.2011, 21:52
Здравствуйте! Я подобрал для вас темы с ответами на вопрос CALLBACK. Нужна помощь (C++):

For_each и аргументы callback-функции; Как передать callback'у больше одного аргумента - C++
Изучаю контейнеры и алгоритмы stl по Майерсу . С непривычки слегка охренел и запутался в них . В общем есть у меня простой вызов...

Нужна помощь начинающему (while). - C++
Собствено вот код: //While DEMO //прога выводит количество выполненых цыклов while #include <stdio.h> #include <lostream.h> int...

Нужна помощь с комментариями. - C++
Нужны комментарии и сделать так, чтобы вводилось только пятизначное число. #include "stdafx.h" #include <stdlib.h> #include...

Нужна помощь с MD5 на Си/Си++ - C++
Мне нужны либо библиотеки, в которых реализована функция-аналог md5() на PHP, либо код. Но библиотеки для висуалс++ не предлагать. Также...

Нужна помощь в исправлении - C++
эта программа расчитывает значения отрезка интегрирования (x1, x2) один для всех трех интегралов, помогите сделать так, чтобы нужно было...

Нужна помощь с циклами - C++
Помогите, пожалуйста, нету никаких идей. Пользователь вводит число. Показать сколько в данном числе чисел и сумму этих чисел. Нужно...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
atomohod
20 / 20 / 1
Регистрация: 01.04.2010
Сообщений: 57
07.11.2011, 11:17  [ТС] #16
Bers, огромнейшее вам спасибо! Разобрался сам и новичкам скилап жесткий сделал! Такое объяснение было бы неплохо в FAQ по CALLBACK'ам записать!
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 11:40 #17
Bers, всё немного не так. В вашем тексте постоянно фигурирует "компилятор подменит xxx на реальное имя метода". Он такой ерундой заниматься вряд ли будет (если и будет, то только в целях оптимизации). Вот, скажем так, контрпример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
 
class Foo
{
public:
    void func1() const
    {
        std::cout << "Foo::func1()" << std::endl;
    }
 
    void func2() const
    {
        std::cout << "Foo::func2()" << std::endl;
    }
 
    void func3() const
    {
        std::cout << "Foo::func3()" << std::endl;
    }
};
 
int main()
{
    typedef void (Foo::*func_ptr)() const;
 
    func_ptr arr[] = {&Foo::func1, &Foo::func2, &Foo::func3};
 
    Foo obj;
 
    while (true)
    {
        int what;
 
        do
        {
            std::cout << ">: ";
            std::cin >> what;
        }
        while (!(what >= 1 && what <= 3));
 
        (obj.*arr[what - 1])();
    }
 
    return 0;
}
Компилятор не сможет тут ничего подменить, ибо он заранее не знает, какой конкретно метод будет вызван, однако всё компилируется и работает.

Вся же проблема была в том, что, действительно, вызывать метод через указатель надо специальным оператором ->* (для указателя на объект класса) или .* (для ссылки или самого объекта).
1
Bers
Заблокирован
07.11.2011, 18:08 #18
silent_1991, понятно, что я утрирую для понимания именно с точки зрения высокоуровневого программиста, а не с точки зрения низко-уровневой механики.

Я сейчас объясню:

Вот смотрите, допустим у нас есть объект, и есть указатель на этот объект. Тогда доступ к объекту через указатель делается так:

ptr -> Method();

Или вот так:

(*ptr).Method();

Во втором варианте в скобочках вычисляется выражение, а именно, "взятие значение по адресу"

Вопрос: что такое "значение по адресу" ?

Ответ на этот вопрос зависит от уровня программиста.
Высокоуровневый программист, вроде меня скажет:

Ответ: данные, чей тип совпадает с типом указателя, который на них указывает.

Ну то есть вместо (*ptr) будит подставлен сам объект, который живет по адресу на который указывает ptr

С указателями на функцию абсолютно аналогично.

Понятно, что с точки зрения низкоуровневого программиста понятие "значение по адресу" может быть более точным, и менее абстрактным.

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

А в записи: (obj.*ptrFunc)() на самом деле происходят два действия:
1. *ptrFunc высчитывает идентификатор функции (адрес её исполняемого кода)
2. Запуск этой функции, с передачей ей в качестве дополнительного аргумента this объекта

Как то так.


/зы На самом деле на высоком уровне такие нюансы реально знать не нужно.
Если программист реально хочется поднять свой скилл, и во всем этом досканально разбираться, то ему нужно учить ассемблер, а не пытаться втиснуть в высокоуровневые рамки низкоуровневые абстракции, имхо.
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 21:44 #19
Bers, с моей точки зрения, язык С++ немного отличается от других языков в этом плане. Сейчас объясню. Я, конечно, на 100 процентов не уверен, но, на мой взгляд, относительно куда меньше программистов на джаве или на шарпе относительно программистов на С++ знают механизм реализации, скажем, виртуальных функций. Они пишут на высоком уровне и им по барабану, что вообще существуют указатели, что также существуют ещё и указатели на функции, и что эти указатели можно собирать в таблицу и заставлять указывать на методы класса. У них есть виртуальные методы как данность, и они ей пользуются. И это, вообще говоря, замечательно. С++ же несколько иной. Хочешь-не хочешь, а он заставит тебя разобраться в этих деталях, если ты хоть немного хочешь понимать, что же там происходит. Мы в этой теме обсуждаем указатели на методы класса, так о каком таком высоком уровне может идти речь?
В общем, моё мнение такое: если браться объяснять кому-либо что-либо, то надо объяснять это корректно и в деталях, а не абстрактно и перевирая истину.
0
Bers
Заблокирован
07.11.2011, 22:13 #20
Хорошо. Я согласен с вами. но ответьте мне на такой вопрос:

C++
1
2
3
4
5
6
7
8
9
10
void Foo() { std::cout << "YES!\n";}  //наш подопытный кролик
typedef void (*myPtr)();   //псевдоним для улучшенной читабельности
 
int main()
{
    myPtr test;  //создадим указатель на функцию
    test=&Foo;    //присвоим указателю значение функции
    (*test)();      //запустим на выполнение функцию, на которую указывает указатель
    return 0;
}
В с++ любое выражение в скобках "высчитывается", и вместо этого выражения подставляется результат расчетов.

в лексеме (*test) ()

что будит поставлено вместо *test ?

На самом деле? Я предполагаю - идентификтор имени функции, который является ни чем иным, как указателем на начало блока памяти, в котором записаны исполняемые инструкции машины.

Но если я прав, тогда в чем же я приверал? А если я не прав - объясните мне, в чем я не прав, что бы я знал.
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 22:21 #21
Bers, да ничего не заменится. Вызов функции произойдёт точно так же, как и при вызове непосредственно через идентификатор, командой call.
0
Bers
Заблокирован
07.11.2011, 22:24 #22
Цитата Сообщение от silent_1991 Посмотреть сообщение
Bers, да ничего не заменится. Вызов функции произойдёт точно так же, как и при вызове непосредственно через идентификатор, командой call.
Вы понимаете, что вы сейчас общаетесь с программистом на с++, а не на ассемблере.
Вы затронули тему того, что программисту с++ нужно знать низкоуровневую механику процессов.

Но это же не значит, что ему нужно знать ассемблер? Вы можете изъясняться в терминах с++, а не ассемблера?
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 22:31 #23
Bers, чтобы вам понять, в чём вы ошиблись (ну или приврали), вам надо понять, что на уровне ассемблера уже нет никаких идентификаторов, только чистые адреса. Вызов функции происходит как передача управления на начало кода по адресу этой функции (грубо, без учёта подготовки стека, передачи параметров и т.д.). Так вот, вызов функции по идентификатору - передача управления по адресу функции. Вызов функции по указателю - то же самое, ведь предварительно в указатель был записан адрес начала функции. В конечном итоге и при вызове функции через идентификатор, и при вызове через указатель произойдёт передача управления в одно и то же место. Компилятор ничего текстово заменять не будет.

Добавлено через 39 секунд
Сразу хочу оговориться, что я не очень компетентен в ассемблере, поэтому в тонкостях могу ошибаться. Но сама идея такая, как я описал.
0
Bers
Заблокирован
07.11.2011, 22:40 #24
ну дык, именно это же я и предполагал! Но поскольку с++ более верхний язык, я заменил понятие "адрес исполняемого кода" на "идентификатор функции"

А Идентификатор функции, и её имя - суть одно и тоже!
компилятор сам подставит вместо имени идентификатор (адрес)
компилятор сам подставит вместо идентификатора адрес (как в случае с указателем на функ)

Точно так же, как имя переменной и идентификатор переменной - одно и тоже (тоже на самом деле указатели на память, где лежат данные)

Добавлено через 3 минуты
тип переменной сообщают компилятору "какая структура данных ожидается"
А имя переменной - адрес, по которому эта структура живёт.


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

Обратишься к имени такой переменной - запустишь этот код
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 23:13 #25
Bers, идентификатор - не адрес. Именно поэтому я и решил внести свои пять копеек. Просто неверно говорить, что компилятор заменит вызов через указатель на вызов через идентификатор.
0
Bers
Заблокирован
07.11.2011, 23:15 #26
Цитата Сообщение от silent_1991 Посмотреть сообщение
Bers, идентификатор - не адрес. Именно поэтому я и решил внести свои пять копеек. Просто неверно говорить, что компилятор заменит вызов через указатель на вызов через идентификатор.
ну так раскройте тему. И расскажите что почем.
Но имейте ввиду - раскрывать тему придётся приплюснутым, а не ассемблистам.
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 23:30 #27
Bers, да чего раскрывать-то? Я уже всё сказал. Идентификатор - текстовое имя. Именно с точки зрения высокого уровня. Потому что никаких текстовых имён на низком уровне нет. И с точки зрения высокого уровня компилятор ничего ни на что не заменяет. А чтобы говорить о том, что же всё-таки он делает, придётся вертеться уже в низком уровне.

 Комментарий модератора 
Bers, а теперь закончили. Я достаточно почитал обсуждений с вашим участием, чтобы понять, что вам нужен спор ради спора. Вы говорите о высоком уровне, рассуждая в терминах низкого. Высокий уровень - std::function, низкий уровень - указатели на функции. И пока вы будете говорить, что компилятор заменяет вызов через указатель на вызов через имя, ссылаясь на высокий уровень, вы просто-напросто будете перевирать термины.
0
Bers
Заблокирован
07.11.2011, 23:39 #28
тему раскрыть в состоянии?
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.11.2011, 23:49 #29
Bers, тема раскрыта уже раза 3. Так что да, в состоянии, как можно было догадаться. Мало того, что я в состоянии раскрыть тему, так я ещё и в состоянии её закрыть, поскольку вы, как обычно, начинаете разводить флейм. Так что...

 Комментарий модератора 
ТС доволен, тема закрыта.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.11.2011, 23:49
Привет! Вот еще темы с ответами:

Нужна помощь по алгоритму - C++
Подскажите литературу, где можно найти алгоритм поиска всех простых циклов в графе граф задан матрицей смежности. Сам использую поиск в...

нужна помощь с рекурсией. - C++
Ребята, кто мне может объяснить доступно рекурсию на элементарном примере? в интернетах в основном примеры с факториалом. вроде с ним...

find_if, нужна помощь - C++
Здравствуйте! Помогите решить проблему пожалуйста. Тут все просто, но у меня куча ошибок ( Вот структура struct HardWare { ...

Нужна помощь с программой - C++
Добрый день!! Помогите пожалуйста с программой, задача состоит в следующем: Все задания выполняются с использованием классов. ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
07.11.2011, 23:49
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru