Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
0 / 0 / 0
Регистрация: 06.10.2018
Сообщений: 1

Вызывается метод родителя, а не наследника. (Проблема с наследованием в параметрах метода)

06.12.2021, 19:21. Показов 2665. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Помогите, пожалуйста, у меня есть класс Entity, в котором работает коллайдер.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Entity:
 
public virtual void Visit(Bullet bullet) { }
public virtual void Visit(EnemyShip enemyShip) { }
public virtual void Visit(PlayerShip playerShip) { }
public virtual void Visit(Asteroid asteroid) { }
public virtual void Visit(Entity entity) { }
 
public virtual void Collide(Entity ent1, IEntityVisitor ent2)
{
     if (this == ent1)
     {
           Console.WriteLine($"Произошла коллизия между объектом {ent1.GetType()} и {ent2.GetType()}");
           ent2.Visit(ent1);
     }
}
 
class Enemy: Entity
 
public override void Visit(Player player){...}
Например, у меня есть 2 объекта Player: Entity и Enemy: Entity;

При вызове метода Visit в методе Collide, где ent1 - Player, а ent2 - Enemy, должен быть вызван метод дочернего класса Enemy :: Visit (Player player), но вызывается метод Entity :: Visit (Entity entity).

При этом при выводе ent1.GetType () пишет, что это Player, а ent2.GetType () - Enemy. Подскажите пожалуйста как реализовать мою идею?

Если я вручную кастую ent1 в Player, все будет работать, но мне нужна универсальность, так как в моей игре больше объектов.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
06.12.2021, 19:21
Ответы с готовыми решениями:

Проблема с наследованием одного класс от другого и методом __init__ у наследника
Сама проблема на строчках 32-33, я не очень понимаю как мне нужно "помочь" питону связать потомка с родителем. И что нужно делать с...

Вызвать метод базового класса из метода наследника
Есть базовый класс с виртуальным методом, выводящим значение его полей. В классе-наследнике есть метод с таким же названием, и он также...

Google_mock тест на вызов метода проваливается, если метод вызывается дважды
Всем добрый день! Занимаюсь тестированием приложения с помощью Google_mock объектов. Необходимо проверить, происходит ли вызов...

7
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
06.12.2021, 21:09
Компилятор c# такого не умеет. Если тип параметра Entity то и самый подходящий метод - Visit(Entity entity);
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
06.12.2021, 21:39
А если поменять вызов на
C#
1
ent2.Visit(this);
?

По идее тогда будет вызываться перегрузка Visit с типом класса, в котором вызов происходит...
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
07.12.2021, 01:28
Цитата Сообщение от TopOwl Посмотреть сообщение
При вызове метода Visit в методе Collide, где ent1 - Player, а ent2 - Enemy, должен быть вызван метод дочернего класса Enemy :: Visit (Player player), но вызывается метод Entity :: Visit (Entity entity).
При этом при выводе ent1.GetType () пишет, что это Player, а ent2.GetType () - Enemy. Подскажите пожалуйста как реализовать мою идею?
Если правильно понял:
C#
1
2
3
4
5
6
7
8
9
10
11
public virtual void Collide(Entity ent1, IEntityVisitor ent2)
{
     if (this == ent1)
     {
           Console.WriteLine($"Произошла коллизия между объектом {ent1.GetType()} и {ent2.GetType()}");
           if(ent1 is Player player)
               ent2.Visit(player);
           else
               ent2.Visit(ent1);
     }
}
Но по вашему коду и объяснениям не понятно какая из перегрузок метода Visit вызывается.
Ведь у ent1 тип IEntityVisitor.
А такой перегрузки я в коде не вижу.

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

В вашем же коде проблема не в том, что компилятор "не видит" переопределения метода в производном классе.
Дело в том, что вы переопредели перегрузку Visit(Player), а тип переменной у вас IEntityVisitor, поэтому компилятор вызывает перегрузку Visit(IEntityVisitor), которую вы не переопределяли.

Добавлено через 9 минут
TopOwl, запутался в вашем коде!
Перепутал переменные.
Мой код верный, но не совсем верны объяснения.

C#
9
10
11
12
13
14
15
16
public virtual void Collide(Entity ent1, IEntityVisitor ent2)
{
     if (this == ent1)
     {
           Console.WriteLine($"Произошла коллизия между объектом {ent1.GetType()} и {ent2.GetType()}");
           ent2.Visit(ent1);
     }
}
В данном случае, компилятор вызывает для объекта ent2 метод Visit(Entity) из интерфейса IEntityVisitor.
Наверное, класс Entity реализует этот интерфейс.
В Enemy вы не переопределяете перегрузку Visit(Entity), поэтому вызывается базовая (и единственная) его реализация.
А чтобы вызвать перегрузку Visit(Player) нужно, как в моём коде, привести объект к нужному типу, чтобы компилятор "понял" какая перегрузка сам нужна.
0
13 / 11 / 2
Регистрация: 07.05.2015
Сообщений: 418
07.12.2021, 09:02
Вам поможет паттерн посетитель с двойной диспетчеризацией. Реализация есть в этой теме
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
07.12.2021, 09:15
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
    interface IEntityVisitor
    {
        void Visit(Bullet bullet);
        void Visit(EnemyShip enemyShip);
        void Visit(PlayerShip playerShip);
        void Visit(Asteroid asteroid);
        void Visit(Entity entity);
        void Visit(Player entity);
    }
    class Entity : IEntityVisitor
    {
        public virtual void Visit(Bullet bullet) { }
        public virtual void Visit(EnemyShip enemyShip) { }
        public virtual void Visit(PlayerShip playerShip) { }
        public virtual void Visit(Asteroid asteroid) { }
        public virtual void Visit(Entity entity)
        {
            Console.WriteLine("Entity(Entity)");
        }
        public virtual void Visit(Player entity) { }
 
        public virtual void Collide(IEntityVisitor other)
        {
            Console.WriteLine($"Произошла коллизия между объектом {this.GetType()} и {other.GetType()}");
            other.Visit(this);
        }
    }
    class Bullet : Entity { }
    class EnemyShip : Entity { }
    class PlayerShip : Entity { }
    class Asteroid : Entity { }
    class Enemy : Entity
    {
        public override void Visit(Player plr)
        {
            Console.WriteLine("Enemy(Player)");
        }
    }
    class Player : Entity
    {
        // с этим override вызывается Enemy::Visit(Player player)
        // а без него Entity::Visit(Entity entity)
        public override void Collide(IEntityVisitor other)
        {
            Console.WriteLine($"Произошла коллизия между объектом {this.GetType()} и {other.GetType()}");
            other.Visit(this);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Entity player = new Player();
            Entity enemy = new Enemy();
            player.Collide(enemy);
        }
    }
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
07.12.2021, 16:54
Цитата Сообщение от Someone007 Посмотреть сообщение
C#
1
2
=25
            other.Visit(this);
А что это меняет?
this типизирован как Entity, поэтому будет вызываться перегрузка Visit(Entity), а TC нужно вызвать перегрузку Visit(Player).
Без приведения ent1 (или this) к типу Player вызывать эту перегрузку не получится.

Цитата Сообщение от Aycon Посмотреть сообщение
Вам поможет паттерн посетитель с двойной диспетчеризацией. Реализация есть в этой теме
Ну.... возможно, но точно не обязательно.
Но ТС и так пытается его реализовать.
Просто у него не получается это сделать.

Цитата Сообщение от TopOwl Посмотреть сообщение
C#
18
19
сlass Enemy: Entity
    public override void Visit(Player player){...}
TopOwl, чё-то только сейчас обратил внимание.
А откуда у вас взялось переопределение перегрузки Visit(Player), если в базовом Entity нет такой виртуальной перегрузки?

TopOwl, дайте полные сигнатуры типов IEntityVisitor, Entity, Enemy, Player и всех перегрузок методов Visit и Collide в них.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
07.12.2021, 17:08
Цитата Сообщение от Элд Хасп Посмотреть сообщение
А что это меняет?
Там в классе Player есть комментарий по этому поводу.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.12.2021, 17:08
Помогаю со студенческими работами здесь

Почему если при вызове метода Foo от типа B, в объекте класса FooImp вызывается метод от А?
Поясните пожалуйста, почему если при вызове метода Foo от типа B, в объекте класса FooImp вызывается метод от А ? public class...

Сборка мусора у наследника и родителя
Добрый день. Есть класс родитель и класс наследник: public abstract class AbstractActivity extends AppCompatActivity { protected...

Доступ к private полю родителя из наследника
Здравствуйте! Изучаю Java, столкнулся с таким вопросом: Допустим, в родительском классе есть private-поле и private-метод. Вопрос: есть...

Доступ к приватному методу наследника через родителя
Тут натолкнулся на интересную штуку. #include <iostream> using namespace std; class A { public: virtual void f() { ...

Лишнее удаление родителя при создании класса наследника
Не могу понять откуда в выводе программы появляется первая надпись "delete A". По идее надписей "delete" должно быть столько же,...


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

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru