Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Присвоение класса в ветвлении

Добрый день всем.


Прошу натолкнуть на мысль, как профессионалы реализовывают следующую задачу:

Есть несколько классов. Методы и свойства в классах абсолютно одинаково именованы, и возвращают аналогичные (типизированные) значения. Реализация методов в классах очень разнится, поэтому это не один класс, а множество классов.

Есть процедура, в которой в зависимости от входных условий необходимо в операторе ветвления объявить переменную выбранного в зависимости от условия класса. Далее, за оператором ветвления необходимо работать с этой переменной.

Но дело в том, что переменная объявленная в операторе ветвления не видна за его пределами. Да, понимаю, можно написать множество функций и в ветвлении обращаться к ним. Но поддержка такого кода тот еще геморр.

Очень прошу подсказать решение. Если вводная не понятна, пишите, попробую добавить, разъяснить.

Спасибо.
Ответ: Опубликую работающий код, вдруг кому....


Public Class Papa
    Public Property param1 As String
    Public Property param2 As Int32
    Public Overridable Function Diablo(inVar As Int32) As Int32
        Return 555
    End Function

End Class


Public Class Child1
    Inherits Papa
    Public Overrides Function Diablo(inVar As Int32) As Int32
        Return inVar * 10
    End Function
End Class

Public Class Child2
    Inherits Papa
    Public Overrides Function diablo(inVar As Int32) As Int32
        Return inVar * 2000
    End Function
End Class
'******************************************************************
Module Module1

    Sub Main()
        Console.WriteLine(selection(1))
        Console.WriteLine(selection(2))
        Console.ReadLine()
    End Sub


'******************************************************************
    Public Function selection(inB As Byte) As Int32
        Dim myPapa As New Papa

        Select Case inB
            Case 1
                myPapa = New Child1
            Case 2
                myPapa = New Child2
        End Select

        Return myPapa.Diablo(inB)

    End Function
End Module
Вопрос: Полный класс для работы с INI-файлами (поддерживает Юникод)

Полный класс для работы с INI-файлами (поддерживает Юникод)

Недавно столкнулся с проблемой запуска своей программы, написанной под русскоязычные системы и с сохранение и чтением настроек в\из файлов INI, на английских системах... Настройки содержали русский текст, который в английской системе просто выглядел как абракадабра и программа его не понимала... В итоге, не поленился, убил много времени, но написал полный класс для работы с INI файлами и сохранение в Юникоде... Никакие WinAPI не применял, все работает через коллекцию типа "словарь" Dictionary.

Особенности в том, что можно перемещать параметры между секциями, можно задавать свои разделители и скобки для обозначения секций, переименовывать секции и параметры, в общем смотрите Description...

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

Код Visual Basic
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
    '*********************************************************************************************************
    '*                                  ПОЛНЫЙ КЛАСС ДЛЯ РАБОТЫ С INI-ФАЙЛАМИ                                *
    '*                                     Автор: Комар Юрий Александрович                                   *
    '*-------------------------------------------------------------------------------------------------------*
    '*  Dim INI As New Full_INI_Class - Присвоение класса переменной с именем "INI" (меняйте как вам удобно) *
    '*-------------------------------------------------------------------------------------------------------*
    '*  LoadFile()                  - Boolean функция, грузит файл, формируя в памяти Dictionary для работы  *
    '*  File_Name                   - String переменная, хранящая имя текущего файла(оставил как Read\Write) *
    '*  AutoSaveFile                - Boolean переменная, хранящая инфо об авто-сохранении при обновлении    *
    '*  SectionBrackets             - String переменная, хранящая брэкеты секций для загрузки и сохранения   *
    '*  ParameterSeparator          - String переменная, хранящая разделитель между Параметром и Значением   *
    '*  Get_Value()                 - String функция, получающая Значение нужного параметра                  *
    '*  Set_Value()                 - Метод, создает или обновляем значение нужного параметра                *
    '*  Get_ListOf_SectionKeys()    - Array функция, получающая список имён всех секций                      *
    '*  Get_ListOf_Parameters()     - Array функция, получающая список имён всех параметров в нужной секции  *
    '*  SectionsCount()             - Integer функция, получающая количество всех секций                     *
    '*  ParametersCount()           - Integer функция, получающая количество параметров в секции или в файле *
    '*  Rename_Section()            - Метод, переименовывающий секцию (если она отсутвует, создает новую)    *
    '*  Rename_Parameter()          - Метод, переименовывающий параметр (если она отсутвует, создает новый)  *
    '*  Delete_Section()            - Метод, удаляющий всю секцию целиком                                    *
    '*  Delete_Parameter()          - Метод, удаляющий параметр вместе с его значением из нужной секции      *
    '*  Move_Parameter_FromTo()     - Метод, перемещающий параметр с его значением из одной секции в другую  *
    '*  SaveFile()                  - Boolean функция, сохраняющая сделанные изменения в файл формата "UTF8" *
    '*-------------------------------------------------------------------------------------------------------*
    '*                                          September 2015                                               *
    '*                          Copyright © 2015 Komar Yury <komar.yury@gmail.com>                           *
    '*********************************************************************************************************
Ответ: #суперкостыли чтение настроек с хаотичного файла
Код vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Dim Sw1 As Boolean = False
        Dim Sw2 As Boolean = False
        Dim Lst1, Lst2 As New List(Of String)
        For Each Line As String In IO.File.ReadAllLines("D:\!.txt", System.Text.Encoding.Default)
            If Line = "[rel]" Then Sw1 = True
            If Line = " " Then Sw1 = False
            If Sw1 = True And Line <> "[rel]" Then
                Lst1.Add(Line.Split("=")(1))
            End If
            '-------
            If Line = "[Analys]" Then Sw2 = True
            If Line = " " Then Sw2 = False
            If Sw2 = True And Line <> "[Analys]" Then
                Lst2.Add(Line.Split("=")(1))
            End If
            '-------
            If Line.Length > 5 AndAlso Line.Substring(0, 4) = "Norm" Then TextBox1.Text = Line.Split("=")(1)
        Next
 
        ListBox1.Items.AddRange(Lst1.ToArray)
        ListBox2.Items.AddRange(Lst2.ToArray)
пример файла

[rel]
1=25
2=25
3=26
4=24
5=26
6=25

Norm=1.0

[Analys]
Pb=0,3
Mg=0.2,3
Вопрос: скрытие операторов присвоения в базовом классе

Здравствуйте!

Я сделал два класса, базовый vidget_base и дочерний vidget_child. Базовый класс, реальный (не абстрактный), но не имеет логического смысла. По этому я хочу спрятать операторы присвоения базового класса.

Прошу совета, как лучше реализовать операторы присваивания в классах vidget_base и vidget_child. У меня есть три работающих варианта. Я всего лишь не могу выбрать правильный.


    class vidget_base
    {
    public:
     
    /* проверяет валидность внутреннего экземпляра. */
    bool is_good() const
    {
    return nullptr != this->_d;
    }
     
    /* разрушает внутренний экземпляр. */
    void release()
    {
    this->_d.reset();
    }
     
    /* и так далее, прочие члены, которые к делу не относятся. */
    ...
     
    protected:
     
    /* конструктор пустого значения. */
    widget_base()
    {
    }
     
    /* конструктор переноса. */
    vidget_base( vidget_base&& other ):
    _d( std::move( other._d ) )
    {
    }
     
    /* деструктор. */
    ~vidget_base()
    {
    this->_d.reset();
    }
     
    #if VARIANT_N
     
    /* оператор переноса. */
    const vidget_base& operator=( vidget_base&& other )
    {
    this->_d = std::move( other._d );
    return *this;
    }
     
    #else
     
    /* оператор переноса. */
    const vidget_base& operator=( vidget_base&& other ) = delete;
     
    #endif
     
    /* указатель на хранимое значение. */
    std::unique_ptr< value_type > _d;
     
    private:
     
    /* конструктор копии невозможен. */
    vidget_base( const vidget_base& other ) = delete;
     
    /* присвоение копии невозможно. */
    const vidget_base& operator=( const vidget_base& other ) = delete;
     
    };
Ну, да, не слишком-то по учебникам. Я подумал, что так будет проще и вроде нормально работает в аналогичных ситуёвинах. Хотя, если заметили глюки, то смело кидайте тапки. Заранее благодарен за них.

На самом деле, ничего там сложного нет, примитивщина полная. Да и для форума, ещё больше упростил.

в дочернем классе, мне нужны операторы присвоения. Но непонятно, как правильно поступить с ними.

    class vidget_child: public vidget_base
    {
    public:
     
    /* конструктор. */
    vidget_child()
    {
    }
     
    /* конструктор переноса. */
    vidget_child( vidget_child&& other ):
    vidget_base( std::move( other ) )
    {
    }
     
    /* деструктор. */
    ~vidget_child()
    {
    }
     
    #if VARIANT_N /* вариант использование оператора переноса из базового класса. */
     
    /* оператор переноса. */
    const vidget_child& operator=( vidget_child&& other )
    {
    return reinterpret_cast< const vidget_child& >( this->vidget_base::operator=( std::move( other ) ) );
    }
     
    #else /* вариант использования скрывающего оператора переноса. */
     
     
    /* оператор переноса. */
    const vidget_child& operator=( vidget_child&& other )
    {
    this->_d = std::move( other._d );
    return *this;
    }
     
    #endif
     
    /* создаёт внутренний экземпляр. */
    void create( const info_type& info )
    {
    this->_d = std::make_unique< value_child_type >( info );
    }
     
    };


Ну, вот, как-то так. Какой вариант выбрать не знаю. А может быть есть ещё варианты.

Заранее отвечу на вопросы:

q: а почему бы не сделать только один vidget_child, и не заморачиватся с двумя классами?

a: должен предупредить, что у меня есть ещё дочерние классы vidget_foo, vidget_bar, которые отличаются от viget_child несколькими методами и главное логическим смыслом. А в класс vidget_base вынесен общий функционал для всех дочерних классов, но объект vidget_base идиологически некорректен. И какое либо использование vidget_base, в пользовательском коде недопустимо. А копипастить классы, мне не хочется.

q: публичное наследование, это по смыслу выражает "vidget_child есть vidget_base". Если это не так, то наследование надо делать protected, а имена расшаривать через using.

a: знаю... Ну.... vidget_base действительно есть vidget_child или vidget_bar и так далее. Просто по смыслу мне нужен абстрактный клас, а виртуализировать не хочу. Отсюда и защищённый конструктор и защищённый деструктор. А остальные члены, нормально подходят, ничего не нужно скрывать.

q: почему конструктор и оператор копирования удалены. И вобще, надо shared_ptr, вместо unique_ptr и будет счастье.

a: shared_ptr действительно хорошая вещь, но в моём случае, (обсуждение которого не относится к сабжу), есть сопутствующие заморочки которые рвут мой мозг, наверняка порвут мозг пользователю класса, и я решил не умничать. Вспомните проблемы с типом string от borland.
Сообщение отредактировано: Eric-S -
Ответ:
Цитата Eric-S @
.. По этому я хочу спрятать операторы присвоения базового класса.

А зачем ?
Из длинных пояснений ничего не понятно.
Вопрос: Наследование. Как сделать так, чтобы присвоение полей исполнилось только в производном классе?

Здравствуйте.
При создании экземпляра
C#
1
DerivedClass instance = new DerivedClass();
С начало выполняется присвоение полям значений в базовом классе, затем в производном.

Походу, конструктор производного класса неявно вызывает конструктор по умолчанию базового класса.
Как сделать так, чтобы присвоение полей исполнилось только в производном классе.

Вариант с удалением присвоения в базовом классе не рассматривается. Но это работает.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
class BaseClass
    {
        // Поля
 
        // Открытое поле.
        public string publicField = "BaseClass.publicField";
 
        // Закрытое поле.
        private string privateField = "BaseClass.privateField";
 
        // Защищенное поле.
        protected string protectedField = "BaseClass.protectedField";
    }
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
39
40
41
42
43
using System;
// Наследование.
 
namespace Inheritance
{
    class BaseClass
    {
        // Поля
 
        // Открытое поле.
        public string publicField = "BaseClass.publicField";
 
        // Закрытое поле.
        private string privateField = "BaseClass.privateField";
 
        // Защищенное поле.
        protected string protectedField = "BaseClass.protectedField";
    }
    class DerivedClass : BaseClass
    {
        // Конструктор.
        public DerivedClass()
        {
            // Изменяем все доступные поля унаследованные от базового класса.
 
            publicField = "DerivedClass.publicField";
            protectedField = "DerivedClass.protectedField";
        }
    }
 
    class Program
    {
        static void Main()
        {
            DerivedClass instance = new DerivedClass();
 
            Console.WriteLine(instance.publicField);
 
            // Delay.
            Console.ReadKey();
        }
    }
}
Ответ: UseMuse, в базовом классе можно сделать несколько конструкторов. Надо сделать такой, который все поля выбивает из аргументов. Пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class A
        {
            public string Title;
             public A():this("A")
            {
 
            }
            public A(string s)
            {
                Title = s;
            }
        }
        public class B : A
        {
            public B(string s):base(s) 
            {
                //тут что-то еще присваиваем
            }
        }
Вопрос: Оператор присвоения в бинарном дереве

Не смог разобраться. Прокомментируйте, будьте добры.
Задание такое, определите стандартный конструктор и функции управления копированием(конструктор копии и оператор присвоения) данным двум классам:
C++
1
2
3
4
5
6
7
8
9
10
11
12
class TreeNode {
    string value;
    int count;
    TreeNode *left;
    TreeNode *right;
public: 
};
//-----------------------------------------
class BinStrTree {
    TreeNode *root;
public:
};
Вопрос, как здесь должен выглядеть оператор присвоения?(в бинарном дереве)
Он же всю связность испортит.
Пытался сделать так, чтобы присваивая, левый операнд удалялся, а правый просто записывался в конец дерева. Думал через деструктор удалять узел, все хорошо, но если узел последний, как сообщить наверх указателю чтоб сюда не показывал(nullptr)...
В отдельную функцию, но тоже самое
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<iostream>
using namespace std;
class TreeNode {
    string value;
    int count;
    TreeNode *left;
    TreeNode *right;
    void erase(TreeNode*&);
public:                                                                 //стандартный конструктор
    TreeNode(string v = "", int c = 0) : value(v), count(c), left(nullptr), right(nullptr) {}
                                                                            // коструктор копии
    TreeNode(TreeNode &tim_obj) : value(tim_obj.value), count(tim_obj.count), left(nullptr), right(nullptr) 
    {
        if (tim_obj.left)
            left = tim_obj.left;
        if (tim_obj.right)
            right = tim_obj.right;
    }
    TreeNode& operator=(TreeNode &) {
              //??????????????????                   ??????????????????????
    }
    ~TreeNode() {}
};
//-----------------------------------------------------------------------
class BinStrTree {
    TreeNode *root;
public:
};
//-----------------------------------------------------------------------
int main() {    
    return 0;
}
//-----------------------------------------------------------------------
void TreeNode::erase(TreeNode *&prev) {
    TreeNode *time_ptr = right, *del;
    if (time_ptr) {
        if (time_ptr->left) {
            while (time_ptr->left->left)
                time_ptr = time_ptr->left;
            auto *pt = time_ptr->left->right;
            del = time_ptr->left;
            time_ptr->left = pt;
            del->right = nullptr;
        }
        else {
            del = time_ptr;
            right = time_ptr->right;
            del->right = nullptr;
        }
    }
    else if (left) {
        del = left;
        left = del->left;
        del->left = nullptr;
    }
    else {
        prev = nullptr;
        delete this;
        return;
    }
    value = del->value;
    count = del->count;
    delete del;
}
Ответ:
Сообщение от yrceus
Да по условию у меня свобода энтузиазму)))
Ну тогда, учитывая, что по условию допускается присвоение узлов, дерево у вес неупорядоченное, так что не надо выдумывать то чего нет, и что противоречит условию.
Вопрос: Создайте класс, содержащий 2 закрытые переменные и открытые функции

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

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 <iostream> 
#include <stdio.h>
#include <conio.h>
 
using namespace std;
 
class treug
{
    float a, b,n,m;
public:
    void set_a (float x, float y);
    int get_a ();
    int set_gip(float e, float c);
};
void treug :: set_a (float x, float y)
{a = x; y = b;}
int treug :: get_a ()
{cout << x << y;}
int treug :: set_gip (float g, float h)
{n = g; m = h;}
int treug :: get_gip ()
{cout << g << h;}
cout << "Гипотенуза =" << n << "Площадь =" << m;
}
 
int main ()
{
    float v, f;
    treug ob1, ob2;
    cout << "Введите значения: ";
    cin >> v >> f;
    ob1.set_a(v);
    ob2.set_gip(f);
    cout << "Вы ввели " << ob1.get_a() << endl;
    cout << "Вы ввели " << ob2.get_gip() << endl;
    system("pause");
    return 0;
}
Укажите мне мои ошибки и помогите их исправить.
Ответ:
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <math.h>
 
/*
Создайте класс
 
    содержащий 2 закрытые переменные
        (катеты прямоугольного треугольника)
 
    открытые функции
        (для присвоения значений закрытым переменным,
         для получения значения закрытых переменных,
         для получения гипотенузы и площади прямоугольного треугольника)
 
Пользователь вводит значения с клавиатуры,
    они передаются в закрытые переменные и используются в функциях.
*/
 
class Triangle
{
public:
    Triangle(double _AB, double _BC) :
        AB(_AB), BC(_BC)
    {}
    ~Triangle() {}
 
    void setAB(double v) { AB = v; }
    void setBC(double v) { BC = v; }
 
    double getAB() { return AB; }
    double getBC() { return BC; }
 
    double getS() { return AB * BC / 2; }
    double getAC() { return sqrt(pow(AB, 2) + pow(BC, 2));; }
 
private:
    double AB, BC;
};
 
int main()
{
    double AB, BC;
 
    std::cout << "Enter two sides of the triangle:" << std::endl;
    std::cin >> AB >> BC;
 
    Triangle t(AB, BC);
 
    std::cout << "AC = " << t.getAC() << std::endl;
    std::cout << "S = " << t.getS() << std::endl;
    return 0;
}
Enter two sides of the triangle:
3
4
AC = 5
S = 6
Для продолжения нажмите любую клавишу . . .
Вопрос: Классы или перечислители?

Предположим есть интерфейс
C#
1
2
3
4
5
public interface IAnimals
{
  string Teeth { get; set; }
  string Color { get; set; }
}
Есть штук5-6 разных классов, для примера:
C#
1
2
3
4
5
6
7
8
9
10
11
public class Fox : IAnimals
{
  public string Teeth { get; set; }
  public string Color { get; set; }
}
public class Wolf: IAnimals
{
  public string Teeth { get; set; }
  public string Color { get; set; }
  public bool IsPredator { get; set; }
}
По ходу выполнения программы нужно переключаться с одного класса на другой приведением. Ну и какое нибудь изображение на форме будет меняться.

Вопрос: так всё и оставить? Или проще замутить что-то типа общего класса со всевозможными полями + Enum?

C#
1
2
3
4
5
6
7
8
9
10
11
12
public class Animals
{
  public string Teeth { get; set; }
  public string Color { get; set; }
  public bool IsPredator { get; set; }
  public Beast WhichOne { get; set;}
}
public enum Beast
{
  Wolf,
  Fox
}
Добавлено через 10 минут
А, забыл, у каждого класса есть свой конструктор, который парсит входные данные и присваивает свойствам значения.
Ответ:
Сообщение от kolorotur
добавление новых видов будет более проблематичным
Виды определены. Никаких добавлений не будет. Точно. Иначе это уже другое ПО.
Сообщение от kolorotur
абстрактный класс Animal и наследовал бы от него конкретные виды
А можно простенький примерчик? Да такой, чтоб можно было перейти из вида в вид.
Смысл какой хочу в итоге получить: чтобы при изменении вида все его свойства заполнялись. Вот к примеру, на входе имеем: "Зис из wolf, хи хэз а мани teeth энд хи из brown". Парсим это дело, получаем что этот Animal волк с зубами. Тут внезапно, пользователь нажимает на картинку с лисичкой и...вид Wolf превращается в Fox с присвоением свойств + в конструкторе Fox выставляем true на IsPredator (всё утрировано, но смысл именно такой). Так же, в каждом классе таскаем входную строку, чтобы при внезапном жмакании картинки на лисичку или на волчонка, заново в конструкторе расставить все необходимые свойства класса.
Запутано?
Не, ну можно вообще убрать и классы и прочее, и просто жонглировать переменными внутри общего класса логики. Но как-то некрасиво будет, не по оопэшному.

Добавлено через 8 минут
Сообщение от skilllab
Запутано?
Итак имею: волка, лису, зайца и тушканчика беззубого. У всех есть общие свойства (цвет, зубы). Но у каждого по отдельности есть свои уникальные свойства.
Что думаю натворить: чтобы при инициализации считывать обычную строку и парсить её на наличие тех или иных свойств. Встречаю "волка" - создаю класс волка, встречаю "тушканчика беззубого", создаю класс. При этом есть комбобокс, переключением которого создаётся класс, соответствующий зверю. Зачем класс? Да потом много чего с его свойствами по логике делаю (присваиваю значения уникальным свойствам для каждого класса) и на выходе к примеру, история про животное)) (ну, не история...так, пару предложений).

Добавлено через 2 минуты
Сейчас всё реализовано через общий большой толстый класс со свойствами и с энумом.
Вопрос: Программа с применением графики, алгоритмов цикла и ветвления

Добрый вечер. Нужно разработать программу с применением графики, применяя алгоритм цикла и ветвления. Помогите пожалуйста.
Ответ:
Код Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uses graphABC;
var i,d,y:byte;
begin
setwindowsize(600,300);
centerwindow;
d:=60;
y:=120;
for i:=1 to 10 do//цикл
 begin
  if odd(i)then setbrushcolor(clRed)//ветвление
  else setbrushcolor(clBlue);
  rectangle((i-1)*d,y,i*d,y+d);
 end
end.
Вопрос: Наследование. Абстрактные классы

Пусть у меня есть абстракт класс "Ship" (корабль) и есть не абстрактный класс его расширяющий "Streamship" (пароход) .У меня есть массив кораблей "ourship". Чтобы считывать корабли и заносить в массив "ourship" я сначала спрашиваю "а какой тип корабля пользователь хочет записать". Если он хочет внести в список "ourship" пароход, то создаю объект пароход "a", заполняю поля этого объекта и i элементу списка "ourship" присваиваю объект пароход "a". но получается так что при присвоении ни одно поле этого i-того элемента из списка "ourship" не заполняется.
===========================================================================
Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  static Ship[] ourship;//массив с кораблями
......
сначала пользователь вводит сколько кораблей в списке кораблей "ourship"
ourship = new Ship[<количество кораблей>];
.....
if (task==1) //Если пользователь решил ввести в список кораблей объект ПАРОХОД
                            { 
                                System.out.println("заполняется запись i="+i);//уже был увеличен индекс добавляемого элемента списка
                                Steamship a = new Steamship();//создается объект ПАРОХОД
 
                                ....заполняются поля объекта ПАРОХОД......
                                
                                Menu.ourship[i]=a;//ourship это список кораблей, то есть i-ым элементом этого списка является объект унаследовавший от абстрактного класса "Корабль" -то есть объект "Пароход"
                                .....
                                
                            }
==========================================================================
почему нельзя было бы так сделать
Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
......
сначала пользователь вводит сколько кораблей в списке "ourship"
.....
if (task==1) //Если пользователь решил ввести в список кораблей объект ПАРОХОД
                            { 
                                System.out.println("заполняется запись i="+i);//В коде уже увеличился индекс
                                ourship[i] = new Steamship();//элемент списка есть объект ПАРОХОД
 
                                ....нужно заполнить поля объекта ПАРОХОД......
                                но здесь, когда я хочу обратиться к полям объекта пароход "Steamship" (ourship[rec].<поля объекта>) , java мне выдает лишь поля абстрактного класса КОРАБЛЬ "Ship"
                             
                                .....
                                
                            }
Ответ: Ну смотри есть у тебя массив
Java(TM) 2 Platform Standard Edition 5.0
1
public  static Ship[] ourship = new Ship[<количество кораблей>];
допустим в массив добавили объект new Steamship(), добавится он успешно т.к. является наследником абстрактного класса. Едем дальше.
При попытки получить элемент массива(наш недавно добавленный new Steamship()), мы получим доступ к интерфейсу класса Ship т.к. массив у нас строго типизированный. Поэтому у тебя вот тут и проблема

"но здесь, когда я хочу обратиться к полям объекта пароход "Steamship" (ourship[rec].<поля объекта>) , java мне выдает лишь поля абстрактного класса КОРАБЛЬ "Ship" "

Если хочешь получить доступ к интерфейсу класса Steamship, то тебе надо прикастовать элемент массива к нужному тебе классу, в данном случае Steamship.
Выглядеть это будет примерно так
Java(TM) 2 Platform Standard Edition 5.0
1
((Steamship)ourship[rec]).getSomeVal();
Надеюсь я тебя правильно понял и помог.
Вопрос: Написание классов и методов к ним

Уважаемые программисты, подскажите как пишутся классы для игр и методы.
Я сейчас пишу игру танчики. Есть класс базовый класс Объект, от этого класса наследуется
классы МойТанк. В классе МойТанк нужно написать функцию, которая проверяет
столкновения со всеми объектами на игровом поле. По мере написания игры появляются новые объекты и
поэтому их тоже нужно учитывать.
В данный момент вот у меня есть метод в классе OnKeyPressed(),который при нажатии стрелок
перемещает мой танк, перед этим проверяя столкновения.

Code
1
2
3
4
5
6
7
8
9
10
11
void MyTank::OnKeyPressed()
{
    Если нажата кнопка вверх
        HelpMoveUp();
    Иначе Если нажата кнопка вниз
        HelpMoveDown();
    Иначе Если кнопка вправо
        HelpMoveDown();
    Иначе Если нажата кнопка влево
        HelpMoveLeft();
}
Одна из функций на псевдокоде вот так выглядит

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MyTank::HelpMoveUp()
{
    Если мой танк сталкивается со стеной
        ничего не делаем;
        
    Если мой танк сталкивается с танком противника
        ничего не делаем;
        
    ...
    И каждый раз при добавлении на игровую карту новых объектов нужно добавлять все новые и новые проверки
    ...
    
    Передвигаем Танк;
}
Основная проблема в том, что при добавлении новых объектов на карту, приходится изменять
классы, которые уже написаны, проверены и отлажены. Приходится дописывать все новые и новые проверки столкновений.
Как это правильно делается? Мне кажется, что я неправильно делаю, и что есть другие способы написания кода.
Заранее спасибо.

Добавлено через 28 минут
И еще пара вопросов по этой теме. Должны ли объекты знать о других объектах на карте? Должен ли Мой Танк знать о том, что на карте есть другие объекты, с которыми он должен как-то взаимодействовать?

Добавлено через 17 минут
Потом хочу написать классы для Аптечки и Травы. И снова придется добавлять проверки, что-то вроде этого

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void MyTank::HelpMoveUp()
{
    Если мой танк сталкивается со стеной
        ничего не делаем;
        
    Если мой танк сталкивается с танком противника
        ничего не делаем;
        
    Если мой танк сталкивается с аптечкой
        прибавляем немного жизней;
        можно ехать вперед;
        
    Если мой танк сталкивается с травой
        можно ехать вперед;
        
    ...
    
    Передвигаем Танк;
}
Ответ: Для этого и существует полиморфизм.
В классе Объект объявляете функции типа "Сталкивается_со_стеной()" виртуальными.
Тогда при присвоении указателю на Объект адреса экземпляра "Мой танк" автоматически получится
МойТанк->Сталкивается_со_стеной()
вместо
Объект->Сталкивается_со_стеной()