Russian Qt Forum
Ноябрь 22, 2024, 23:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Указатели на члены класса внутри класса  (Прочитано 9867 раз)
andi
Гость
« : Январь 29, 2007, 09:09 »

Хочется реализовать такую задумку.
Код:

class cl{
public:
cl(){ func = &func1; }
int (*func)(int); // указатель на метод класса
int func1(int i){return i+1; } // сами методы
int func2(int i){return i+2; }
int func3(int i){return i+3; }
int f(int i){ return (*func)(i); }
};


Пока не получается. Компилятор ругается на присваивание указателя функции. Всевозможные варианты с добавлением имени класса и :: к положительному результату не привели. Скурил уже все книги и доки по С++.
Вообще возможен ли данный вариант?

добавлено спустя 23 минуты:

 Присвоение удалось осуществить такой конструкцией
func = &cl::func1;
при этом func объявляется так:
int (cl::*func)(int)

Но после всего этого вызвать функцию не могу.
пробовал так:
return func(i);
return (*func)(i);
return (cl::*func)(i)

ни в какую.
Записан
Вудруф
Гость
« Ответ #1 : Январь 29, 2007, 12:04 »

Правильно, именно так они и объявляются.

А вызывать их надо так:
cl obj;
int (cl::*func)(int);
func = &cl::func1;
int i = obj.(*ptr)(1);

Или через указатель...
Фишка здесь в том, что член-функция должна знать, где в памяти расположены данные, с которыми она работает.
Записан
andi
Гость
« Ответ #2 : Январь 29, 2007, 12:11 »

Мне такой вариант не подходит.
Этот пример я в Шилдтсе видел.
Надо изловчиться так, чтобы вызывать функцию внутри метода класса, где еще нет экземпляра.
Записан
Вудруф
Гость
« Ответ #3 : Январь 29, 2007, 13:18 »

Учите мат. часть. Если функции НЕ работают с данными класса, они должны быть статическими.
Дальше: а зачем вам такой класс? ИМХО, лучше определить отдельное пространство имён, куда и поместить все ваши функции и переменные. При этом определения функции видны всем (находятся в h-файле), а реализация И переменные - скрыты в cpp-файле...
Записан
andi
Гость
« Ответ #4 : Январь 30, 2007, 05:54 »

Вялая попытка сменить задачу не пройдет.
Пример класса, конечно не так прост как показано.
Скажем так, есть приватные данные(коэффициенты), которые доступны членам класса, и которые через публичные методы можно менять. Так вот func1 - funcN выдает различные линейные комбинации этих коэффициентов и входящих данных. Таким образом, задаем коэффициенты, задаем номер функции. И через публичный вызов типа int getValue(int val) получаем необходимый результат, без дополнительных расходов на if() case() и for().
Записан
Вудруф
Гость
« Ответ #5 : Январь 30, 2007, 07:34 »

Таких классов с разными коэффициентами в программе должно быть несколько?
Предлагаю немного подумать: Как можно вызвать функцию класса, если у вас ещё нет экземпляра? Откуда функция будет брать эти самые коэффициенты?
Если у вас все коэффициенты - статические переменные, то и все функции должны быть статическими. В таком случае вызвать их без экземпляра класса получится, однако... в таком случае класс вообще не имеет смысла создавать, коэффициенты существуют глобально, иными словами у вас всегда имеется один экземпляр. В таком случае лучше отказаться от класса и создать пространство имён, где и объявить все необходимые функции, а нужные переменные (поскольку они внутри пространства имён, доступные только в пределах одной единицы компиляции) поместить в файл реализации.
Понятно? Что именно разъяснить подробнее?
Записан
andi
Гость
« Ответ #6 : Январь 30, 2007, 08:20 »

Экземпляров классов будет несколько, у каждого свои коэффициенты. Но сами линейные комбинации (полиномы различных степеней) у всех одинаковые.
И вот мне нужно обращаясь к разным экземплярам проводить вычисления с теми коэффициентами которые в него записаны и с тем полиномом который в нем указан как рабочий (путем присваивания указателя на конкретную функцию).
Вот так я это вижу.
Если бы был один экземпляр и все на С. Присвоить и использовать указатель на функцию было бы легче чем два байта переслать (это уже пройденный этап, работало все отлично). Но вот в С++  это реализовать не получается. Хотя в чем тут сложность адресной арифметики для компилятора не понимаю. Я конечно понимаю, что проверка типов и все такое. Но почему нельзя в классе сделать кучу одинаковых (по параметрам) функций и указатель на такую функцию. Присваивать этому указателю адрес этой функции и использовать его внутри для личных нужд класса.
Записан
Вудруф
Гость
« Ответ #7 : Январь 30, 2007, 11:13 »

Так, я тебя не понимаю.
Цитировать

Надо изловчиться так, чтобы вызывать функцию внутри метода класса, где еще нет экземпляра

Цитировать

Экземпляров классов будет несколько, у каждого свои коэффициенты.

Откуда вызываемая функция будет знать, где лежат эти самые коэффициенты? Функция - это КОД, работающий с какими-то данными. Для класса не создаётся столько копий КОДА, сколько у тебя создано экземпляров. Есть только копии ДАННЫХ. Иначе это привело бы к неэффективной работе с классами.
Итак, у нас есть одна копия КОДА и несколько копий ДАННЫХ. Именно поэтому функцию нужно вызывать для конкретного экземпляра (через указатель или напрямую), таким образом мы показываем, где лежат необходимые данные.

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

Нужно только немного задуматься, как это реализовано, и всё становится на свои места. Или Страуструпа перечитать, там это написано.

Итог: Ты можешь создавать указатели, ты можешь их присваивать, просто при запуске функции тебе нужно показать, где лежат необходимые им данные. Путём указания, где лежит экземпляр класса.
Записан
andi
Гость
« Ответ #8 : Январь 30, 2007, 12:42 »

Блин, придется написать весь класс:
Код:

class cl{
private:
 int k0,k1,k2,k3;
 int (*func)(int); // указатель на метод класса
public:
 cl(){ func = &func1; }
 int setParam(int m0,m1,m2,m3,type){
  k0=m0; k1=m1; k2=m2; k3=m4;
  switch(type){
   case 1: func = &func1; break;
   case 2: func = &func2; break;
   case 3: func = &func3; break;
  }
 }
 int func1(int i){return i+k0-k1; } // сами методы
 int func2(int i){return i+k1-k2; }
 int func3(int i){return i+k2-k3; }
 int getValue(int i){ return (*func)(i); }
};

void main(){
 cl *ob1 = new cl(); ob1->setParam(1,2,3,4,1);
 cl *ob2 = new cl(); ob2->setParam(10,20,30,40,2);
 cl *ob3 = new cl(); ob3->setParam(100,200,300,400,3);
 cout<<ob1->getValue(1)<<endl;
 cout<<ob2->getValue(2)<<endl;
 cout<<ob3->getValue(3)<<endl;
}


Вот примерно то, что нужно. Ни больше ни меньше.
И вопрос, как правильно написать этот класс, чтобы работало так как написано.

Насчет первой указанной цитаты. Я неправильно выразился. Нужно не "вызвать", а описать ее в объявлении. В любом случае я ее буду вызвать после того как все проинициализирую и выделю память.

По поводу Итого: как реализовать то, что описано в "итого"?
Запуск функции по указателю осуществляется внутри класса, сам указатель тоже расположен внутри класса.
И еще наводящий вопрос, можно ли внутри класса получить указатель на экземпляр класса?


[/code]
Записан
Вудруф
Гость
« Ответ #9 : Январь 30, 2007, 16:34 »

Полностью рабочая программа:
Код:

#include <iostream>

class cl
{
private:
int k0, k1, k2, k3;
int (cl::*func)(int);
public:
cl() : func (&cl::func1) {}
void setParam (int m0, int m1, int m2, int m3, int type)
{
k0 = m0;
k1 = m1;
k2 = m2;
k3 = m3;
switch (type)
{
case 1:
func = &cl::func1;
break;
case 2:
func = &cl::func2;
break;
case 3:
func = &cl::func3;
break;
}
}
int func1 (int i);
int func2 (int i);
int func3 (int i);
int getValue (int i);
};

int cl::func1 (int i)
{
return i + k0 - k1;
}

int cl::func2 (int i)
{
return i + k1 - k2;
}

int cl::func3 (int i)
{
return i + k2 - k3;
}

int cl::getValue (int i)
{
return (this ->* func)(i);
}

int main()
{
cl * ob1 = new cl();
ob1 -> setParam (1, 2, 3, 4, 1);
cl * ob2 = new cl();
ob2 -> setParam (10, 20, 30, 40, 2);
cl * ob3 = new cl();
ob3 -> setParam (100, 200, 300, 400, 3);
std::cout << ob1 -> getValue (1) << '\n';
std::cout << ob2 -> getValue (2) << '\n';
std::cout << ob3 -> getValue (3) << '\n';
}


добавлено спустя 4 минуты:

 Кстати, я всё-таки порекомендую потестировать, действительно ли такой вариант быстрее, чем switch... Здесь мы вынуждены func1...func3 реализовывать отдельно, в итоге мы при вызове разыменовываем указатель, а затем вызываем функцию (заносим параметры в стек, выполняем код).
В случае switch мы можем сделать inline-функцию, которая уберёт описанные затраты.
Записан
andi
Гость
« Ответ #10 : Январь 31, 2007, 05:37 »

Код:

int cl::getValue (int i)
{
   return (this ->* func)(i);
}

Вот этого мне и не хватало.
А насчет скорости... Возможно вы и правы, черт его знает какие у С++ накладный расходы в данном случае.
Записан
Вудруф
Гость
« Ответ #11 : Январь 31, 2007, 08:09 »

Такие же, как и у Си. Просто здесь появилась возможность делать встраиваемые (inline) функции, что может быть более эффективным.
Записан
kolobok0
Гость
« Ответ #12 : Февраль 08, 2007, 20:11 »

Цитата: "Вудруф"
...   void setParam (int m0, int m1, int m2, int m3, int type)....В случае switch мы можем сделать inline-функцию, которая уберёт описанные затраты.


если type превратить (всё равно используется некий код 1-2-3) в описание типа (без создания его экземпляра) - то это даст возможность сделать всё то же самое, только
1) без свитча
2) с меньшим кол-вом параметров.
3) с меньшей глубиной вызовов по коду. Или по другому - сразу на уровне компиляции вызвать необходимый метод...
4) более компактно и элегантно...

с уважением
(круглый)
Записан
andi
Гость
« Ответ #13 : Май 22, 2007, 06:03 »

2kolobok0:
А можно подробней про ваше предложение?
Еще раз уточню, что какая именно функция должна вызывать станет известно, только после того как из конфига считаются параметры работы. На этапе компиляции это не известно.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.102 секунд. Запросов: 20.