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

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

Войти
Регистрация
Восстановить пароль
 
dovskr
0 / 0 / 0
Регистрация: 13.03.2013
Сообщений: 18
#1

Почему не стоит создавать массив объектов? - C++

18.03.2013, 00:00. Просмотров 517. Ответов 5
Метки нет (Все метки)

Нам преподаватель сказал, что создавать массив объектов лучше не стоит(надо создавать массив указателей на объекты) так как при наследовании что-то там происходит с преобразованиями типов и привёл пример того, как не стоит писать. Вот пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A
{
    public
        virtual int f()=0;
}
 
class B: public A
{
    public
        int f();
}
 
A *index(A* p,int i)
{
    return &p[i];
}
 
....
....
B peet[Count]
A* p=index(peet,2)
....
....

Можете пояснить подробно что тут такого происходит когда в функцию передаётся указатель на массив объектов и почему так нельзя писать(как тут преобразование типов влияет)?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.03.2013, 00:00
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Почему не стоит создавать массив объектов? (C++):

как создавать динамическое число объектов - C++
Помогите: как создавать динамическое число объектов, напишите, пожалуйста программу, в которой создается N объектов

Можно ли в классе создавать массив переменной длинны. Например динамический массив? - C++
Динамические массивы привлекают больше. :)

Почему я не могу создавать темы в разделе фриланс->предложения фрилансеров? - C++
Почему?

Как создавать массивы объектов, и как к ним обращаться? - C++
как создавать массивы объектов и как к ним обращаться? вот что пишет создатель самого си в своей книге - получается что нельзя...

Почему не стоит использовать ^(XOR) в swap - C++
Прочитал статейку, http://betterexplained.com/articles/swap-two-variables-using-xor/ Что-то не до понял, почему нельзя...

Можно ли создавать массив строк (string)? - C++
А можно ли в с++ создавать массив строк? Например string a ?

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
DU
1483 / 1059 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.03.2013, 01:51 #2
подробности есть в книге
Наиболее эффективное использование C++. 35 новых рекомендаций по улучшению ваших программ и проектов
Автор: Скотт Мейерс
Правило 3. Никогда не используйте полиморфизм в массивах
http://rsdn.ru/res/book/cpp/most_effective_cpp.xml

Связано с глюками, которые возникнуть при арифметики с указателями.
Доступ по индексу - это один из таких случаев.
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
struct Base
{
   char ch;
};
 
struct Der : public Base
{
    char ch2;
};
 
//В плюсах указатель на Der преобразуется в указатель на Base;
//В нашем случае размер объектов типа Base меньше объектов типа Der.
//Создаем массив Der;
Der derArr[10];
 
// Получаем указатель на первый элемент, преобразованный к указателю на Base
Base* baseArrPtr = derArr;
 
// Теперь пытаемся изменить значение символа второго элемента массива:
baseArrPtr[1].ch = 'c';
 
//baseArrPtr[1].ch = 'c'; эквивалентно следующему:
Base* ptr = (baseArrPtr + 1);
ptr->ch = 'c';
 
//При арифметике с указателями они наращиваются в зависимости от размера
//объекта, а размер определяется типом указателя. В нашем случае это указатель
//на Base. Но размер Base меньше чем размер Der.
//это значит, что указатель ptr будет указывать не на второй элемент исходного массива
//производных объектов Der, а куда-то в середину первого объекта этого массива. А
//это ошибка.
kravam
быдлокодер
1694 / 881 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.03.2013, 02:35 #3
Вот так ты должен был написать:
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:
        virtual int f()=0;
};
 
class B: public A
{
    public:
        int f() {};
};
 
A *index(A* p,int i)
{
    return &p[i];
}
 
 
int main () {
 int Count= 10;
 B peet[Count];
 A* p=index(peet,2);
 p->f();
 return 0;
}
Учитывая, что код демонстрационный, он вполне себе нормален. Какие всего этого последствия? Ну-во первых у тебя на данный момент занята память под Count элементов типа B. Оно тебе надо? В то время как по факту нужен всего один элемент- второй. Поэтому делаем так:

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
#include <stdio.h>
 
class A
{
    public:
        virtual int f()=0;
};
 
class B: public A
{
    public:
        int f() {};
};
 
A *index(A** p,int i)
{
    return p[i];
}
 
 
int main () {
 
 int Count= 10;
 
 //Вот массив указателей
 B* peet[Count];
 A* p=index((A**)peet,2);
 
 
 //Теперь p должен указывать на элемент типа B, но этого элемента нет!
 //мы ведь не создали ни один элемент типа B, мы создали только указатели на них!
 //исправим это положение, создадим такой элемент
 p= new B;
 
 //И вызываем функцию
 p->f();
 return 0;
}
то есть сейчас строчкой B* peet[Count]; я создаю массив указателей, а он по определению не может быть больше массива элементов, а может быть меньше. То есть экономится память и время на конструирование. Ведь в дальнейшем я создаю всё-таки один элемент строчкой p= new B; но это ведь не 10!

Цитата Сообщение от dovskr Посмотреть сообщение
Можете пояснить подробно что тут такого происходит когда в функцию передаётся указатель на массив объектов
Ничё особенного не происходит-то. В функцию index передаёдся адрес нулевого объекта массива beep и этото же адрес и возвращается. А ты что думал?
dovskr
0 / 0 / 0
Регистрация: 13.03.2013
Сообщений: 18
18.03.2013, 03:19  [ТС] #4
Спасибо, теперь вроде бы ясно почему такое происходит. Но теперь возник другой вопрос.
Пусть есть классы A и B.
В классе А объявлен public int Ax, В классе B объявлен public int Bx;
Класс C наследуется от них обоих. Насколько я понимаю в памяти объект класса C будет состоять из данных класса A, после которых идут данные класса B и после них уже идут данные класса С.

Напишем например




C++
1
2
3
4
5
6
7
8
9
C x;
A* PointerA=&x;
B* PointerB=&x;
int a,b;
a=PointerA->Ax;  // Тут всё должно по идее сработать
b=PointerB->Bx;// А вот тут сработает ли(действительно ли вернёт то что находится в Bx)? Ведь копия класса B 
                    // будет располагаться в памяти после копии класса А
                   // а указатель B фактически указывает на начало копии объекта класса С, но сам является указателем
                  // на объект класса B
Добавлено через 15 минут
kravam
быдлокодер
1694 / 881 / 44
Регистрация: 04.06.2008
Сообщений: 5,441
18.03.2013, 05:19 #5
Ну так ты возьми да проверь, чё гадать-то на кофейной гуще?
Цитата Сообщение от dovskr Посмотреть сообщение
указатель B фактически указывает на начало копии объекта класса С, но сам является указателем // на объект класса B
Мало ли что куда указывает, сказано же, раз класс наследник то он наследует поля родительского класса. Можно то есть считать, что в классе C есть поле Bx. PointerB на что указывает? На x. x имеет Bx? Имеет. Значит, b=PointerB->Bx; сработает правильно, беспокоиться не о чем.

Если чё: в памяти нет ни объекта класса B, ни объекта класса A. Есть объект класса C состоящий из двух полей: Ax и Bx. Проверь:

C++
1
 printf ("%d\n", sizeof (x));
DU
1483 / 1059 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.03.2013, 09:52 #6
правильнее все таки говорить что класс C состоит из подобъектов A и B;
и если брать указатели на них, то они не будут одинаковыми:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
C c;
C* cptr = &c;
A* aptr = &c;
B* bptr = &c;
 
// кастим, чтобы можно было сравнивать указатели без ворнингов и ошибок
const void* cptr2 = cptr;
const void* aptr2 = aptr;
const void* bptr2 = bptr;
 
// для случая наследования: class C : public A, pubic B {};
cptr2 == aptr2; 
cptr2 != bptr2; 
aptr2 != bptr2;
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.03.2013, 09:52
Привет! Вот еще темы с ответами:

Почему не компилируется код в котором описание класса стоит после main - C++
Изучаю с++ по книге за 21 день. Почему когда я пишу так, то не компилируется: #include &lt;iostream&gt; #include &lt;conio.h&gt; #include...

Почему возможно задать массив с размером -1 (почему такое вообще компилируется)? - C++
Всем привет. Долгое время не писал на плюсах, решил пройтись по основам, вспомнить. По непонятным для меня причинам этот код...

Почему после конструктора первого класса стоит двоеточие и имя переменной, а не инициализация? - C++
#include &lt;iostream&gt; template &lt;typename T&gt; class first { public: T value; first (T n) : value(n) {} virtual...

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


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

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

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