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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.91
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
#1

Может ли объект-член, или объект-элемент достучаться к содержащему его? - C++

14.03.2014, 09:27. Просмотров 1588. Ответов 58
Метки нет (Все метки)

Предположим,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A
{
 ...
};
class B
{
 ....
 A a;
...
};
class C
{
 ...
 A *a;
 ...
}
...
B b1;
B *b2;
C c;
size_t i;
...
. Может ли b1.a достучаться до b1, b2[i].a к b2[i], а c.a[i] - до c? Данные по c.a и b2 могут перемещаться reallocом.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.03.2014, 09:27
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Может ли объект-член, или объект-элемент достучаться к содержащему его? (C++):

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

Недопустимый неполный тип , или как передать в функцию указатель на объект класса , или просто объект - C++
Други мои , кодеры. Не могу я ни как передать в функцию объект класса , или что еще лучше(для меня , так как учусь работать с указателями)...

Основы: указатель на объект или объект, что выбрать? - C++
Не до конца понимаю (или вообще не понимаю) когда лучше использовать указатель на объект, а когда объект. Например: // есть класс ...

Может ли функция иметь аргументом другую функцию или объект? - C++
Внимание тупой вопрос )) А может ли функция иметь аргументом другую функцию или объект?

Реализовать двухсвязный список. Каждый элемент списка может содержать один объект - C++
Здравствуйте, мне нужно было реализовать двухсвязный список. Каждый элемент списка может содержать один объект. Объект может быть трех...

при вызове конструктора присваивания надо возвращать ссыль на объект или сам объект. Смысл? Значения нужных полей меняютмся и без этого! - C++
Друзья! Обнаружил пробел в знаниях. Собсно, вопрос в теме. Дополню лишь: поля объекта меняются на нужные значения и безо всякого возврата...

58
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 13:35  [ТС] #16
Цитата Сообщение от DrOffset Посмотреть сообщение
class A;
class Aa
{
public:
* * Aa(A & parent) : parent_(parent) {}
private:
* * A & parent_;
};
class Ab
{
public:
* * Ab(A & parent) : parent_(parent) {}
private:
* * A & parent_;
};
class A
{
public:
* * A() : a(*this), b(*this) {}
private:
* * friend class Aa; // для полного доступа. Можно убрать, если он не нужен.
* * friend class Ab;
Aa a;
* * Ab b;
};
, ейси.
C++
1
b2=(B*) reaaloc((void*)b2, NeCount);
, адреса агрегирующих объектов могут в этот момент поменяться.
0
aLarman
642 / 563 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
14.03.2014, 13:39 #17
realloc вроде копирует, не должны, вот только тогда в агрегирующем классе могут слететь ссылки на агрегированные объекты
0
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 13:40  [ТС] #18
Цитата Сообщение от DrOffset Посмотреть сообщение
Стоит заметить ,что у этого есть свои ограничения. Например, в конструкторах и деструкторах таких классов нельзя обращаться к данным родителя. Т.к. они могут быть либо еще не созданы, либо уже уничтожены. Собственно поэтому подобная фича не доступна по умолчанию.
Уже инициализируется агрегированный объект, а агрегирующего ещё нет. Очень интересно. Или для агрегированный ещё не удалялся, а агрегирующий уже удалён. Также весело.

Добавлено через 1 минуту
Цитата Сообщение от aLarman Посмотреть сообщение
realloc вроде копирует, не должны, вот только тогда в агрегирующем классе могут слететь ссылки на агрегированные объекты
Какого они слетят? Все внутриобъектные смещения константы в пределах класса.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.03.2014, 14:08 #19
Цитата Сообщение от taras atavin Посмотреть сообщение
адреса агрегирующих объектов могут в этот момент поменяться.
Чтобы этого не происходило надо пользоваться С++ средствами для перераспределения памяти, которые вызовут соответствующие деструкторы, соответствующие конструкторы копирования и т.д. Либо реализовывать это поверх realloc самостоятельно. realloc в чистом виде не годится для любых сложны C++ классов, а не только в этом случае.

Добавлено через 9 минут
taras atavin,
Посмотри на досуге вот этот пример
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <vector>
#include <cstdio>
 
class MyTest
{
public:
    MyTest()               {  printf("%s\n", __PRETTY_FUNCTION__); }
    MyTest(MyTest const &) {  printf("%s\n", __PRETTY_FUNCTION__); }
    ~MyTest()              {  printf("%s\n", __PRETTY_FUNCTION__); }
};
 
int main()
{
    std::vector<MyTest> myTest;
    myTest.reserve(1);
 
    myTest.push_back(MyTest());
    puts("------");
    myTest.push_back(MyTest());
    puts("------");
    myTest.push_back(MyTest());
    puts("------");
}
если хранить приведенный мной выше класс в таком контейнере, то рассогласования ссылок внутри объектов никогда не произодет. Т.к. будут гарантированно вызваны все конструкторы и деструкторы.
А вот копировать с помощью, например, memcpy не-POD типы в С++ в принципе не очень хорошая идея.
0
Alex5
1086 / 747 / 116
Регистрация: 12.04.2010
Сообщений: 1,907
14.03.2014, 17:25 #20
Пример с использованием указателей на члены класса. (Возможно, не будет работать для любого компилятора.)
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
struct B
{
    void* func();
};
 
struct A
{
    int m; 
    int n;
    B b1;
    B b2;
};
 
void* B::func()
{
    B A::* q; // указатель на член класса ( член, имеющий тип B )
    q = &A::b1; //  0x00000008
 
    int* pInt2 = reinterpret_cast<int*>( &q ); // *pInt2 == 8 , т.е. sizeof(A::m) + sizeof(A::n)
 
    // чтобы получить адрес объекта-агрегата, из this вычитаем 8
    void* parent = reinterpret_cast<char*>(this) - *pInt2;
    return parent;
}
 
int main()
{
    A a;
    cout << "\n &a    " << &a << endl;
 
    void* p = a.b1.func();
    cout << "\n result of  a.b1.func()  " << p << endl;
 
    // ... 
}
0
Миниатюры
Может ли объект-член, или объект-элемент достучаться к содержащему его?  
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 17:34  [ТС] #21
Цитата Сообщение от Alex5 Посмотреть сообщение
B A::* q; // указатель на член класса ( член, имеющий тип B )
* * q = &A::b1; // *0x00000008
Это что за синтаксис такой?
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.03.2014, 17:43 #22
taras atavin, обычный для указателей на члены класса. Это по сути как раз те самые смещения. Поэтому их получают через определение класса
&A::b1
, не через объект.
А вот reinterpret_cast в этом случае - нехорошо. Пример не учитывает выравнивание, к тому же компилятор для не standard-layout классов может менять местами поля в целях оптимизации. Ну и достаточно просто добавить в такой класс еще одно поле и не провести соответствующих изменений в коде доступа к полям, то все смещения "поплывут".
0
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 17:45  [ТС] #23
Цитата Сообщение от DrOffset Посмотреть сообщение
taras atavin, обычный для указателей на члены класса. Это по сути как раз те самые смещения. Поэтому их получают через определение класса
&A::b1
, не через объект.
Расшифруй как для нуба в кубе.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.03.2014, 18:04 #24
taras atavin,
Есть объект типа А. Назовем его obj.
У него естественно есть адрес.
Адрес есть и у каждого его поля. Указатель на это поле можно получить двумя способами. Первый способ - это получить указатель на объект поля.
C++
1
int * pA = &obj.a;
А можно (второй способ) получить смещение относительно базы.
C++
1
int A::* offsetA = &A::a;
Ну вот такая запись, она означает, что мы взяли относительный указатель на поле типа int в классе А.
Для доступа по этому смещению нам нужна база. Это базой может служить непосредственно объект типа А.
C++
1
2
A obj;
int v = (obj.*offsetA);
тут мы получили значение поля а, смещение которого мы запомнили в offsetA, у объекта obj.
либо, можно использовать для этого указатель:
C++
1
2
A * pObj;
int v = (pObj->*offsetA);
Для указатель на методы те же правила. Только в отличие от данных, нельзя получить абсолютный адрес метода, только вот такой относительный.
0
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 18:07  [ТС] #25
Нда. А кто мешает юзать имена полей и поручить смещения компилятору?
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.03.2014, 18:14 #26
taras atavin, никто. Просто иногда это бывает полезно.

Добавлено через 6 минут
Лично я не находил применения таким указателям на данные. Но зато использовал указатели на методы (у них синтаксис похож, только параметры еще добавляются). Это полезно при реализации делегатов.
0
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.03.2014, 18:23  [ТС] #27
Цитата Сообщение от Alex5 Посмотреть сообщение
B A::* q; // указатель на член класса ( член, имеющий тип B )
* * q = &A::b1; // *0x00000008
int* pInt2 = reinterpret_cast<int*>( &q ); // *pInt2 == 8 , т.е. sizeof(A::m) + sizeof(A::n)
// чтобы получить адрес объекта-агрегата, из this вычитаем 8
* * void* parent = reinterpret_cast<char*>(this) - *pInt2;
* * return parent;
А откуда известно, что this указывает именно на b1? Что выведет:
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
struct B
{
    void* func();
};
 
struct A
{
    int m; 
    int n;
    B b1;
    B b2;
};
 
void* B::func()
{
    B A::* q; // указатель на член класса ( член, имеющий тип B )
    q = &A::b1; //  0x00000008
 
    int* pInt2 = reinterpret_cast<int*>( &q ); // *pInt2 == 8 , т.е. sizeof(A::m) + sizeof(A::n)
 
    // чтобы получить адрес объекта-агрегата, из this вычитаем 8
    void* parent = reinterpret_cast<char*>(this) - *pInt2;
    return parent;
}
 
int main()
{
    A a;
    cout << "\n &a    " << &a << endl;
 
    void* p = a.b2.func();
    cout << "\n result of  a.b2.func()  " << p << endl;
 
    // ... 
}
? А ведь по условию функцией может владеть даже элемент динамического массива.
0
Alex5
1086 / 747 / 116
Регистрация: 12.04.2010
Сообщений: 1,907
14.03.2014, 20:18 #28
Цитата Сообщение от DrOffset Посмотреть сообщение
Пример не учитывает выравнивание, к тому же компилятор для не standard-layout классов может менять местами поля в целях оптимизации.
Данный пример как раз учитывает выравнивание.
Цитата Сообщение от DrOffset Посмотреть сообщение
Ну и достаточно просто добавить в такой класс еще одно поле ...
Давайте посмотрим.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
/* добавим поле char, больше никаких изменений в коде нет (см. сообщение #20) */
struct A
{
    char c; 
    // ... 
};
/* Результат: 
 
 &a    0019F9EC
 
 result of  a.b1.func()  0019F9EC
 
*/
Цитата Сообщение от DrOffset Посмотреть сообщение
А вот reinterpret_cast в этом случае - нехорошо
Это верно, но по другой причине. А именно, указатель на член класса определяет смещение поля объекта.
Но вряд ли можно полагаться на то, что он просто равен смещению. Зависимость может быть какой-то другой.
(Вариант 1. Указатель на член класса равен смещению+1. Значение 0 зарезервируем для недействительного указателя.)
(Вариант 2. Указатель на член класса равен смещению. Недействительный указатель: 0xFFFFFFFF.)
(Другие варианты ... )
Так что, если использовать .* или ->* компилятор всё расшифрует правильно. А при использовании reinterpret_cast возникнет ошибка.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.03.2014, 23:29 #29
Цитата Сообщение от Alex5 Посмотреть сообщение
Данный пример как раз учитывает выравнивание.
В принципе было бы достаточно этой фразы. Действительно, учитывает. А "магическая" константа была в комментарии, а не в коде, на что я и не обратил внимания
0
taras atavin
3570 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
15.03.2014, 07:37  [ТС] #30
Данный пример не учитывает, что однотипных членов может быть несколько.
0
15.03.2014, 07:37
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.03.2014, 07:37
Привет! Вот еще темы с ответами:

Как достать объект-контейнер, а не его элемент - C++
Добрый вечер всем. Возник вопрос. Я читал Страуструпа и на одной из его глав, есть упражнение по созданию класса-контейнера, в...

Объект osteram& или как его вывести в переменную ? - C++
Здравствуйте Объект osteram&amp; или как его вывести в переменную ? cin... cout... printf... scanf А вот как же вывети поток...

Указатель на объект из указателя на член класса - C++
Что как-то сей вопрос ставит меня в тупик. class A { int i; } obj; int main()

интерфейс, в методе которого создается объект типа IDictionary и возвращается ссылка на этот объект - C++
Привет всем. Необходимо реализовать интерфейс, в методе которого создается объект типа IDictionary и возвращается ссылка на этот объект. Не...


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

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

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