Показать полную графическую версию : Порядок объявления классов (нужна помощь)
Здравствуйте.
нужен совет и помощь по устранению нижеизложенной проблемы. (работающий код не требуется, просто скажите что сделать, дабы компилятор не выдавал ошибки)
Код в файле (если прикрепился). Там только интерфейс.
При компиляции порядка 12-ти ошибок (считает, что массив пассажиров на самом деле массив переменных неизвестного типа). При перемещении включённого в Bus класса Passanger кол-во ошибок меняется.(после Автобуса - 9,перед- 12).
Прошу объяснить зелёному.-(
у тебя "круговая" зависимость. В пассажирах определена функция с аргументом типа автобус, а в автобусе определены типа пассажиры.
Завтра в книге полюбопытствую, может и есть в Cях какие хитрые конструкции. Но сомневаюсь, пока мое решение - поправить структуру, убрав "круговую" зависимость
у тебя "круговая" зависимость. В пассажирах определена функция с аргументом типа автобус, а в автобусе определены типа пассажиры.
Завтра в книге полюбопытствую, может и есть в Cях какие хитрые конструкции. Но сомневаюсь, пока мое решение - поправить структуру, убрав "круговую" зависимост »
Если найдётся хоть какое-то решение, при котором не надо сносить часть класса - буду очень благодарен.
Пока я вижу только 3 выхода:
1) Снести функцию "платить" у пассажира (не вариант)
2) Снести поле у автобуса (тем более не вариант)
3) метод платить связать с классом транспортное средство, добавляя поле "деньги", которое "грузовику" нафиг не надо. (очень плохой вариант, но из 3-х зол...)
З.Ы.Дело в том, что работая над прогой закоментил спорные моменты, думая, что "потом как-нибудь разберусь и исправлю". Когда наступило "потом" выяснилось, что если что-то изменить придётся менять значительную часть.-( Кроме этого ещё статические и динамические диаграммы... В общем, ничего приятного.
почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (int pass[50] ?)
почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (int pass[50] ?) »
Не, мне то всё равно, вот только на этих самых пассажирах нужно показать реализацию композиции (агрегации).
El Scorpio
20-05-2011, 07:39
Прошу объяснить зелёному.-( »
Зрелый программист предлагает сначала объявить нужные классы
// Объявляем нужные классы
class Bus;
class Minivan;
class Passanger;
//................
class Bus
{
// Описываем функции класса, в том числе с параметрами типа Passanger
};
class Passanger
{
//Описываем функции класса, в том числе с параметрами типа Bus и т.д
};
P.S.
А сам код всё-таки стоит переработать
El Scorpio
20-05-2011, 07:55
Ещё несколько ошибок:
class Minivan:public Bus,public Truck
Классы Bus и Truck являются производными от класса Vehicle. Таким образом, объект класса Minivan будет содержать два комплекта полей класса Vehicle.
Исправляется это использованием "виртуальных классов" (class Bus:virtual public Vehicle и class Truck:virtual public Vehicle). Теперь class Minivan:public Bus,public Truck создаст только один комплект полей для общего класса Vehicle
Ну и конечно-же
char* GetCompany(void);
int SetCompany(char*);
Если рассудок и жизнь дороги вам, держитесь подальше от торфяных болот указателей на символьные массивы. Ошибки в процессах выделения памяти и контроля размерности - одни из самых серьёзных и трудновычисляемых проблем.
Если в программе нужно использовать строки, используйте объекты строк (string, AnsiString и т.д.)
P.S.
class Passanger
{
int pay(Bus&);
int pay(Minivan&);
};
Во-первых, здесь нагляднее будет использовать указатели вместо ссылок. Во-вторых, поскольку класс Minivan является потомком класса Bus, объявление отдельной функции для него - лишнее и даже нежелательное.
El Scorpio, спасибо большое за помощь.)
Теперь ошибок, найденных компилятором, две, при чём идентичные по содержанию: класс Bus использует неопределённый класс Passanger; (уже исправлено)
И отдельное спасибо за советы. Лишний раз убеждаюсь, что действительно ценные советы и опыт можно получить не столько от университета, сколько от знающих людей. Может потому что первый курс, может из-за изобилия предметов типа матана, дискретной математики и т.п.
По поводу указателей - дурацкие требования к программе. Или используй указатель на символьный массив, или используй объекты строк, но только написанные собой.)
Во-первых, здесь нагляднее будет использовать указатели вместо ссылок. Во-вторых, поскольку класс Minivan является потомком класса Bus, объявление отдельной функции для него - лишнее и даже нежелательное. »
А если, скажем, цена проезда в Автобусе и Minivan-е разная? Тогда как лучше поступить?
Delirium
21-05-2011, 00:49
действительно ценные советы и опыт можно получить не столько от университета, сколько от знающих людей »
Универ учит читать и пользоваться документацией. А знающие люди направляют в нужное русло :) А предметы типа матана и дискретки потом очень помогут, хотя бы в понимании логики и дискретных вычислений :)
El Scorpio
21-05-2011, 13:59
По поводу указателей - дурацкие требования к программе. Или используй указатель на символьный массив, или используй объекты строк, но только написанные собой.) »
Советую потратить пять минут на написание своего класса строк. Управление памятью можно реализовать через функцию realloc
class MyString
{
private:
int len;
char *srt;
bool TestIndex (index)
{Сам напишешь}
public:
int SetLen (int New)
{
if (New >= 0)
{
str = realloc (str, New * sizeof (char));
// Как работает эта функция, читай в справке
len = New;
}
return len;
}
int GetLen (void) const
{return len;}
const char* GetStr (void) const
{return str;}
~MyString (void)
{free (srt);}
MyString (void)
{len = 0; str = NULL;}
MyString (const MyString &Copy)
{ // Сам напишешь };
MyString (const char *Ptr)
{ // Сам напишешь };
MyString& operator= (const MyString &Copy)
{ // Сам напишешь };
MyString& operator= (const char *Ptr)
{ // Сам напишешь };
char& operator[] (int index)
{ // Сам напишешь };
char operator[] (int index) const
{ // Сам напишешь };
};
Учти, что реальная длина строкового массива всегда на один элемент больше видимого текста - в этой ячейке хранится спецсимвол с кодом 0, который означает "конец массива" и используется во многих функциях работы с символьными массивами
Советую потратить пять минут на написание своего класса строк. Управление памятью можно реализовать через функцию realloc »
Учту. Видимо, действительно того стоит.
Ещё несколько вопросов из числа глупых:
Допустим у меня массив объектов "Пассажир"(внутри Автобуса).
Passanger pass[200];
При этом все 200 создаются сразу же конструктором по умолчанию? Т.е. добавления(в "пустой" автобус)/удаления(по номеру) по одному пассажиру не получится?
El Scorpio
22-05-2011, 09:16
Допустим у меня массив объектов "Пассажир"(внутри Автобуса).
Passanger pass[200];
При этом все 200 создаются сразу же конструктором по умолчанию? Т.е. добавления(в "пустой" автобус)/удаления(по номеру) по одному пассажиру не получится? »
Любой конструктор при создании объекта заполняет исходными значениями все поля простых типов, а для полей сложных типов автоматически вызывает конструкторы.
Обойти этот момент можно через "списки инициализации"
// Вариант 1
TPoint::TPoint (int NewX, int NewY)
{ x = NewX; y = NewY;}
// Вариант 2
TPoint::TPoint (int NewX, int NewY): x (NewX), y (NewY)
{}
В первом варианте поля x и y сначала заполняются нулями, а уже потом в них записываются нужные значения. Во втором варианте поля x и y сразу заполняются нужными значениями
Конкретно в этом случае каждый раз при создании объекта класса Bus для массива pass[200] будет 200 раз вызван конструктор Passanger (void).
Именно по-этому статичные массивы в полях классов используются редко. Лучше использовать класс динамических массивов (vector, DynamicArray), размер которых будет задаваться по мере необходимости.
P.S.
Никогда не задавай размеры массивов числами - используй константы
const int ArrSize = 20;
///
int Arr [ArrSize];
///
for (int i = 0; i < ArrSize; i++)
{}
В такой форме при необходимости изменения размеров массива достаточно будет заменить одну цифру, а не менять числа по всему коду программы (с риском пропустить и тем самым создать ошибку)
El Scorpio, спасибо. Внял вашим советам, всё отлично.
Ещё один небольшой вопрос:
int x,y,z;
cin>>x; (1)
cin>>y; (2)
cin>>z; (3)
(1)Пользователь вводит вместо чисел строку\слишком большое число. Как следствие - ввод (2-3) не запрашивается.
Насколько я понимаю, эта проблема связана с буфером? Как её обойти помимо проверки введённых значений каждый раз?
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC