PDA

Показать полную графическую версию : Порядок объявления классов (нужна помощь)


Glorh
19-05-2011, 16:37
Здравствуйте.

нужен совет и помощь по устранению нижеизложенной проблемы. (работающий код не требуется, просто скажите что сделать, дабы компилятор не выдавал ошибки)

Код в файле (если прикрепился). Там только интерфейс.

При компиляции порядка 12-ти ошибок (считает, что массив пассажиров на самом деле массив переменных неизвестного типа). При перемещении включённого в Bus класса Passanger кол-во ошибок меняется.(после Автобуса - 9,перед- 12).

Прошу объяснить зелёному.-(

lxa85
19-05-2011, 22:03
у тебя "круговая" зависимость. В пассажирах определена функция с аргументом типа автобус, а в автобусе определены типа пассажиры.
Завтра в книге полюбопытствую, может и есть в Cях какие хитрые конструкции. Но сомневаюсь, пока мое решение - поправить структуру, убрав "круговую" зависимость

Glorh
19-05-2011, 22:25
у тебя "круговая" зависимость. В пассажирах определена функция с аргументом типа автобус, а в автобусе определены типа пассажиры.
Завтра в книге полюбопытствую, может и есть в Cях какие хитрые конструкции. Но сомневаюсь, пока мое решение - поправить структуру, убрав "круговую" зависимост »

Если найдётся хоть какое-то решение, при котором не надо сносить часть класса - буду очень благодарен.

Пока я вижу только 3 выхода:
1) Снести функцию "платить" у пассажира (не вариант)
2) Снести поле у автобуса (тем более не вариант)
3) метод платить связать с классом транспортное средство, добавляя поле "деньги", которое "грузовику" нафиг не надо. (очень плохой вариант, но из 3-х зол...)

З.Ы.Дело в том, что работая над прогой закоментил спорные моменты, думая, что "потом как-нибудь разберусь и исправлю". Когда наступило "потом" выяснилось, что если что-то изменить придётся менять значительную часть.-( Кроме этого ещё статические и динамические диаграммы... В общем, ничего приятного.

lxa85
19-05-2011, 22:35
почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (int pass[50] ?)

Glorh
20-05-2011, 00:12
почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (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, объявление отдельной функции для него - лишнее и даже нежелательное.

Glorh
20-05-2011, 08:37
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, который означает "конец массива" и используется во многих функциях работы с символьными массивами

Glorh
21-05-2011, 15:26
Советую потратить пять минут на написание своего класса строк. Управление памятью можно реализовать через функцию 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++)
{}

В такой форме при необходимости изменения размеров массива достаточно будет заменить одну цифру, а не менять числа по всему коду программы (с риском пропустить и тем самым создать ошибку)

Glorh
23-05-2011, 23:29
El Scorpio, спасибо. Внял вашим советам, всё отлично.

Ещё один небольшой вопрос:
int x,y,z;
cin>>x; (1)
cin>>y; (2)
cin>>z; (3)
(1)Пользователь вводит вместо чисел строку\слишком большое число. Как следствие - ввод (2-3) не запрашивается.
Насколько я понимаю, эта проблема связана с буфером? Как её обойти помимо проверки введённых значений каждый раз?




© OSzone.net 2001-2012