Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Порядок объявления классов (нужна помощь) (http://forum.oszone.net/showthread.php?t=207208)

Glorh 19-05-2011 16:37 1679139

Порядок объявления классов (нужна помощь)
 
Вложений: 1
  • 1.txt (1.80 KB, скачиваний: 22)
Здравствуйте.

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

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

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

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

lxa85 19-05-2011 22:03 1679271

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

Glorh 19-05-2011 22:25 1679280

Цитата:

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

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

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

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

lxa85 19-05-2011 22:35 1679288

почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (int pass[50] ?)

Glorh 20-05-2011 00:12 1679336

Цитата:

Цитата lxa85
почему поле вместимость у автобуса измеряется в "пассажирах"? Чем измерение в "целых" попугаях не понравилось? (int pass[50] ?) »

Не, мне то всё равно, вот только на этих самых пассажирах нужно показать реализацию композиции (агрегации).

El Scorpio 20-05-2011 07:39 1679410

Цитата:

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

Зрелый программист предлагает сначала объявить нужные классы

Код:

// Объявляем нужные классы
class Bus;
class Minivan;
class Passanger;
//................
class Bus
{
// Описываем функции класса, в том числе с параметрами типа Passanger
};
class Passanger
{
//Описываем функции класса, в том числе с параметрами типа Bus и т.д
};

P.S.
А сам код всё-таки стоит переработать

El Scorpio 20-05-2011 07:55 1679413

Ещё несколько ошибок:
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 1679429

El Scorpio, спасибо большое за помощь.)

Теперь ошибок, найденных компилятором, две, при чём идентичные по содержанию: класс Bus использует неопределённый класс Passanger; (уже исправлено)

И отдельное спасибо за советы. Лишний раз убеждаюсь, что действительно ценные советы и опыт можно получить не столько от университета, сколько от знающих людей. Может потому что первый курс, может из-за изобилия предметов типа матана, дискретной математики и т.п.

По поводу указателей - дурацкие требования к программе. Или используй указатель на символьный массив, или используй объекты строк, но только написанные собой.)
Цитата:

Цитата El Scorpio
Во-первых, здесь нагляднее будет использовать указатели вместо ссылок. Во-вторых, поскольку класс Minivan является потомком класса Bus, объявление отдельной функции для него - лишнее и даже нежелательное. »

А если, скажем, цена проезда в Автобусе и Minivan-е разная? Тогда как лучше поступить?

Delirium 21-05-2011 00:49 1679928

Цитата:

Цитата Glorh
действительно ценные советы и опыт можно получить не столько от университета, сколько от знающих людей »

Универ учит читать и пользоваться документацией. А знающие люди направляют в нужное русло :) А предметы типа матана и дискретки потом очень помогут, хотя бы в понимании логики и дискретных вычислений :)

El Scorpio 21-05-2011 13:59 1680099

Цитата:

Цитата Glorh
По поводу указателей - дурацкие требования к программе. Или используй указатель на символьный массив, или используй объекты строк, но только написанные собой.) »

Советую потратить пять минут на написание своего класса строк. Управление памятью можно реализовать через функцию 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 1680145

Цитата:

Цитата El Scorpio
Советую потратить пять минут на написание своего класса строк. Управление памятью можно реализовать через функцию realloc »

Учту. Видимо, действительно того стоит.

Ещё несколько вопросов из числа глупых:

Допустим у меня массив объектов "Пассажир"(внутри Автобуса).
Passanger pass[200];
При этом все 200 создаются сразу же конструктором по умолчанию? Т.е. добавления(в "пустой" автобус)/удаления(по номеру) по одному пассажиру не получится?

El Scorpio 22-05-2011 09:16 1680445

Цитата:

Цитата Glorh
Допустим у меня массив объектов "Пассажир"(внутри Автобуса).
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 1681403

El Scorpio, спасибо. Внял вашим советам, всё отлично.

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


Время: 17:53.

Время: 17:53.
© OSzone.net 2001-