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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.92
Alberto_Timakov
1 / 1 / 0
Регистрация: 21.11.2011
Сообщений: 183
#1

указатели на элементы класса - C++

11.09.2012, 18:57. Просмотров 1879. Ответов 22
Метки нет (Все метки)

Здравствуйте!
есть код:

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
class A
{
    public:
    void C(void){return;}
        static int D(void){return 0;}
    int a;
        static int d;
};
 
int main(int argc, char** argv)
{
        A a_obj;
    int (A:: *p)= &A::a;// - работает
        //int *p= &a_obj.a; - не работает
        //int *p= &A::a; - не работает
        void (A::*f)(void)= &A::C; // - работает
        //void (*f)(void)= &A::C; - Не работает
        //void (*f)(void)= &a_obj.C; - Не работает
        int *e1= &a_obj.a;// - Работает
        int *e2= &A::a;// - Работает
        int (*F1)(void)= &A::D;// - работает
        int (*F2)(void)= &a_obj.D;// - работает
    system("Pause");
    return 0;
}
Знаю, что в не статическую функцию Неявно передается this, т.е. выходит вместо параметра (void), по сути параметр (this) в методе C и т.к. преобразование из в void (A::*)() в void * невозможно, то ошибка, а как тогда объяснить ошибку связанную со строкой :
C++
1
2
3
  
      //int *p= &a_obj.a; - не работает
        //int *p= &A::a; - не работает
в Т.А. Павловская "C/C++ прог. на яз. высокого уровня" пишут, что указатель на элемент класса в отличии от указателя на обычную переменную или функцию, ссылается не на определенный адрес памяти, а больше похож на индекс в массиве, т.к. задает смещение

Вот не могли бы вы поподробней рассказать про то что из себя этот указатель представляет,а то не очень понятно... и есть что-то, что позволяет достать адрес элемента класса, начинается по-моему на __co...и как-то связанно с __thiscall

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

Указатели и элементы класса - C++
Суть проблемы: есть класс neuro. в нём есть элемент данных double *inputs; // входыесть независимый от первого класс auction в нём...

Указатели на метод класса - C++
Допустим есть 2 класса: class A { public: A() {} ~A() {} virtual void Draw(GLuint shader)

Указатели на члены класса - C++
Здравствуйте, В коде при вызове функции print() из CL2 вызывается print() из CL1. Подскажите, где грабли. Заранее спасибо. ...

Указатели на объекты класса - C++
Здравствуйте. помогите новичку. есть проблема с освоением программирования на VC++. пытаюсь скомпилировать вот этот пример из книги: ...

Конструкторы и указатели на объект класса - C++
Добрый вечер. Помогите, пожалуйста, прояснить 2 вещи: 1) В чём будет отличие между конструкторами: int a; //Исп. оператор...

Потоки и указатели (в поток вставить объект класса) - C++
Есть структура: class shapka{ public: int* prev; int n; int* next; } }; Нужно в поток вставить объект класса, потом...

22
Герц
524 / 341 / 4
Регистрация: 05.11.2010
Сообщений: 1,077
Записей в блоге: 1
11.09.2012, 23:58 #16
Кодовые слова: таблица виртуальных функций.
У класса нет таблицы виртуальных функций пока отсутствует хотя бы один метод, помеченный спецификатором virtual.
http://liveworkspace.org/code/c7d21d894d1699caff7e53255f346c27
При появлении виртуальной функции размер пустого класса возрос с 1 байта до 4, то есть как раз на размер указателя на vtable для 32-битной машины.
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
12.09.2012, 00:12 #17
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Кодовые слова: таблица виртуальных функций.
Наверное и невиртуальные методы могут адресоваться посредством таблицы. Для меня важно, что это функции, то есть их указатель - указатель на функцию возвращающую значение типа... и объявляющую аргументы типа..., и это не простой указатель на встроенный тип. Целая структура. Вдобавок (и главное, если речь о методе), - он связан с классом. Нестатический метод без экземпляра вызвать нельзя, поскольку без указателя на экземпляр (this) нет доступа к полям. Но сути это не меняет. Ведь this в этом случае передается, не для того, чтобы метод найти, а для того чтобы указать методу класса, к полям какого экземпляра ему обращаться.
0
DU
1483 / 1129 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
12.09.2012, 04:06 #18
Если подумать, то для вызова невиртуального метода через указатель,
живой объект не очень то и нужен. Ведь не нужно шарится по таблице
виртуальных функция для поиска правильной функции. С указателем
на виртуальный метод совсем другое, потому что таблица виртуальных
функция находится по смещению относительно адреса объекта, для
которого этот метод зовется. Что стандарт говорит относительно
первого утверждения - хз, но студия и компилер из ссылки
делают вызов невиртуального метода имея нулевой указатель на
объект. То, что в методе this оказывается равным нулю - это
уже отдельная история. Если к полям класса не обращатся,
ничего не упадет.


http://liveworkspace.org/code/036ec377892b2d28d07b4592b61a7bfd


Далее, вот например указатель на метод:
typedef void (Foo::*MethodPtr)();
Тут нигде не кодируется его виртуальность\невиртуальность.
Поэтому, можно прикинуть, что компиляторы реализуют
указатели на методы в виде какой-то структуры,
в которой есть флажок о виртуальности\невиртуальности метода
и другие поля, позволяющие сделать правильный вызов.
Для невиртуальных методов будет использоваться поле,
в которой указатель на метод похож на указатели на свободные
функции (с учетом того, что сигнатура несколько расширена
за счет неявной передачи this и может быть соглашения о
вызове другие). А вот в случае указателя на виртулальный
метод используются другие поля. Например просто индекс
функции в таблице виртуальных функций, ведь для вызова
виртуального метода через указатель нужен сам объект
для определения, где таблица функций и смещение на указатель
к нужному методу.

Ну примерно это можно было бы описать так:

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
46
47
48
49
50
51
52
53
54
55
56
57
58
typedef void (Foo::*MethodPtr)();
//примерно эквивалентно
struct MethodPtr
{
  bool isVirtual;
  void (*nonVirtPtr)(Foo*);
  int virtFunPtrOffset;
};
 
{
  MethodPtr nonVirtPtr = &Foo::NonVirtual;
  MethodPtr virtPtr = &Foo::Virtual;
 
  // после этого поля у ptr будут такими:
  //nonvirtPtr.isVirtual == false;
  //nonvirtPtr.NonVirtPtr == указатель на функцию
  //nonvirtPtr.virtFunPtrOffset == неопределено. пусть будет -1
 
  //virtPtr.isVirtual == true;
  //virtPtr.NonVirtPtr == не определено. пусть будет 0
  //virtPtr.virtFunPtrOffset == смещение в таблице. пусть будет 0 (т.е. первый метод в таблице)
 
   //далее код вызова превращается в следующее
 
   MethodPtr ptr = nonVirtPtr;
   //MethodPtr ptr = virtPtr;
 
   Foo* foo = 0;
   foo->*method)();
   if (ptr.isVirtual)
   {
      // Получение указателя на табличку. Может крашнутся,
      // а может и нет. Просто вернется указатель на хз что.
      // Ведь чтобы получить указатель на таблицу, компилятору
      // нужно знать лишь адрес объекта и сместится относительно
      // него на определенное известное во время компиляции значение.
      // нет особого смысла проверять корректность адреса объекта,
      // к нему достаточно прибавить нужное смещение. Если адрес
      // объекта будет кривой, то и адрес таблички тоже будет кривым
      // жопа случится при попытке вызвать что-то из этой таблицы.
      
      VTable vtbl = GetVTableOfObject(foo);
      // В этом месте у нас есть таблица и индекс функции в этой
      // таблице. Сигнатура метода тоже известна.
      (vtbl[ptr.virtFuncOffset])(foo);
 
      // в случае кривого указателя на таблицу вот это:
      // vtbl[ptr.virtFuncOffset] - тоже кривое.
 
   }
   else
   {
     // в этой ветке для вызова метода сам объект вроде как и не нужен.
     // метод вызовится ну а крашнется или нет уже зависит от кода 
     // самого метода. Главное что метод вызовится.
     (ptr.nonVirtPtr)(foo);
   }
}
0
DU
1483 / 1129 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
12.09.2012, 04:06 #19
Если подумать, то для вызова невиртуального метода через указатель,
живой объект не очень то и нужен. Ведь не нужно шарится по таблице
виртуальных функция для поиска правильной функции. С указателем
на виртуальный метод совсем другое, потому что таблица виртуальных
функция находится по смещению относительно адреса объекта, для
которого этот метод зовется. Что стандарт говорит относительно
первого утверждения - хз, но студия и компилер из ссылки
делают вызов невиртуального метода имея нулевой указатель на
объект. То, что в методе this оказывается равным нулю - это
уже отдельная история. Если к полям класса не обращатся,
ничего не упадет.


http://liveworkspace.org/code/036ec377892b2d28d07b4592b61a7bfd


Далее, вот например указатель на метод:
typedef void (Foo::*MethodPtr)();
Тут нигде не кодируется его виртуальность\невиртуальность.
Поэтому, можно прикинуть, что компиляторы реализуют
указатели на методы в виде какой-то структуры,
в которой есть флажок о виртуальности\невиртуальности метода
и другие поля, позволяющие сделать правильный вызов.
Для невиртуальных методов будет использоваться поле,
в которой указатель на метод похож на указатели на свободные
функции (с учетом того, что сигнатура несколько расширена
за счет неявной передачи this и может быть соглашения о
вызове другие). А вот в случае указателя на виртулальный
метод используются другие поля. Например просто индекс
функции в таблице виртуальных функций, ведь для вызова
виртуального метода через указатель нужен сам объект
для определения, где таблица функций и смещение в этой
таблице чтобы получить указатель на правильную функцию.
Флажок виртуальности\невиртуальности проверяется в рантайме.

Ну примерно это можно было бы описать так:

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
typedef void (Foo::*MethodPtr)();
//примерно эквивалентно
struct MethodPtr
{
  bool isVirtual;
  void (*nonVirtPtr)(Foo*); // указатель на функцию (как бы свободную), которая возвращает void и принимает Foo*
  int virtFunPtrOffset;
};
 
{
  MethodPtr nonVirtPtr = &Foo::NonVirtual;
  MethodPtr virtPtr = &Foo::Virtual;
 
  // после этого поля у указателей будут такими:
  //nonvirtPtr.isVirtual == false;
  //nonvirtPtr.NonVirtPtr == указатель на функцию
  //nonvirtPtr.virtFunPtrOffset == неопределено. пусть будет -1
 
  //virtPtr.isVirtual == true;
  //virtPtr.NonVirtPtr == не определено. пусть будет 0
  //virtPtr.virtFunPtrOffset == смещение в таблице. пусть будет 0 (т.е. первый метод в таблице)
 
 
 
   MethodPtr methodPtr = nonVirtPtr;
   //MethodPtr methodPtr = virtPtr;
 
   Foo* foo = 0;
   (foo->*methodPtr)();
   //этот код превращается примерно в следующее
   if (methodPtr.isVirtual)
   {
      // Получение указателя на табличку. Может крашнутся,
      // а может и нет. Просто вернется указатель на хз что.
      // Ведь чтобы получить указатель на таблицу, компилятору
      // нужно знать лишь адрес объекта и сместится относительно
      // него на определенное известное во время компиляции значение.
      // нет особого смысла проверять корректность адреса объекта,
      // к нему достаточно прибавить нужное смещение. Если адрес
      // объекта будет кривой, то и адрес таблички тоже будет кривым
      // жопа случится при попытке вызвать что-то из этой таблицы.
      
      VTable vtbl = GetVTableOfObject(foo);
      // В этом месте у нас есть таблица и индекс функции в этой
      // таблице. Сигнатура метода тоже известна.
      (vtbl[methodPtr.virtFuncOffset])(foo);
 
      // в случае кривого указателя на таблицу вот это:
      // vtbl[methodPtr.virtFuncOffset] - тоже кривое.
 
   }
   else
   {
     // в этой ветке для вызова метода сам объект вроде как и не нужен.
     // метод вызовится ну а крашнется или нет уже зависит от кода 
     // самого метода. Главное что метод вызовится.
     (methodPtr.nonVirtPtr)(foo);
   }
}
Ну и возможно еще есть какие-то хитрости в преобразовании указателей на объекты в случае указателя на виртуальный метод и множественном наследовании с и без виртуальной базы (виртуальных базовых классов). Там уже нужно смотреть на компоновку объектов в памяти.
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
12.09.2012, 13:56 #20
DU, я совсем не уверен в том, что сейчас скажу. Но есть надежда, что если кого-то зацепит, - получим более конкретную информацию.
С моей точки зрения объект наследующего класса, объявленный через указатель базового класса не теряет ведь, своей типовой принадлежности (конструктор же свой используется), поэтому информация о смещении, в данном случае находится в базовом классе. В экземпляре, - информация о том относительно какого класса (наследника) смещение, ну и конечно this...

Не по теме:


Вообще, для программирования на ЯП высокого уровня это скорее предположения. Да и знаний маловато. Отсюда и легенды. Вот одна из них.

pikki-wedia:
У индейцев племени Нав...ах каких охотников, есть легенда о том, что душа хахаскера честно использовавшего STL и придерживавшегося хорошего стиля, обязательно будет обласкана Великим Мани Тоо. Он поместит её в вечно зелёную виртуальную страну, где ходят тучные стада грациозных рекурсий и и мохнатых инлайнов!
Мечта. Если о рекурсиях ещё есть более менее твердые сведения, то инлайн - зверь совершенно загадочный. Но говорят если очень попросить Мани Тоо, он может материализовать инлайн!
Простите за оффтоп

0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,386
Завершенные тесты: 1
12.09.2012, 16:56 #21
Что за смещение? Если Вы говорите о доступе к виртуальным методам, то при компиляции класса содержащего виртуальную функцию ( -ции ) создается таблица виртуальных функций. Фактически каждый объект класса содержит указатель на данную таблицу для своего класса. При обращении через указатель базового класса, указатель разыменовывается, и мы получаем объект производного ( или того же базового класса ). Указатель на таблицу ( vtable ) находится в начале объекта, то есть объект с него начинается. Далее просто берется этот указатель, и разыменовывается. И так мы попадаем непосредственно к vtable, все что остается программе - это сделать смещение, если потребуется ( если виртуальных функций несколько, и требуется не первая в таблице функция ), на некое количество байт ( количество кратно размеру указателя системы ) , и разыменовать полученный адрес, что бы получить доступ к самой функции.
0
Alberto_Timakov
1 / 1 / 0
Регистрация: 21.11.2011
Сообщений: 183
12.09.2012, 17:45  [ТС] #22
а обычные функции в vtable не записываются? А то в примерах в инете, приводятся обычно примеры классов содержащих одну вирт функцию и обычную и рисуют вирт. табл. где и обычная функция и вирт. функция находятся...А поля класса где сохр?
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,386
Завершенные тесты: 1
12.09.2012, 18:03 #23
Обычные функции не записываются, для них происходит статическое связывание на этапе компиляции. Я описал лишь один из возможных, и самых частых реализаций полиморфизма. Стандартом языка не оговорена его реализация.
1
12.09.2012, 18:03
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.09.2012, 18:03
Привет! Вот еще темы с ответами:

Как на практике используются указатели на члены класса - C++
Вопрос №3. А как на практике используются указатели на члены класса? Они в реальном коде вообще используется? Приведите пример когда они...

Указатели и классы: присвоение значения элементу массива, который является полем класса - C++
Доброго времени суток, делал задание, где надо создать класс, полем которого будет массив указателей на другие массивы и перегрузить...

Указатели и указатели на указатели, а также типы данных - C++
Недавно начал изучать Си, перешел с Delphi. Много непонятного и пока процесс идет медленно. Накачал литературы, буду изучать) Щас...

Не вводятся элементы в массив(указатели) - C++
Здравствуйте! У меня возникла проблема с указателями... Я хочу сделать функцию, которая организует ввод данных в статический массив, и...


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

Или воспользуйтесь поиском по форуму:
23
Ответ Создать тему
Опции темы

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