LINUX.ORG.RU

Прикольная задачка. Решите?


0

1

Есть вот такой код (ява)

class Parent {
	public void outMe() {
		System.out.println("Parent");		
	}
}

class Child extends Parent {
	public void outMe() {
		System.out.println("Child");
	}
}

class Receiver {
	public void receive(Parent p) {
		System.out.println("Receiver");
		p.outMe();
	}
}

class AdvancedReceiver extends Receiver {
	public void receive(Child c) {
		System.out.println("AdvancedReceiver");
		c.outMe();
	}
}

public class InheritanceTest {
	public static void main(String[] args) {
		Parent child1 = new Child();
		AdvancedReceiver advancedReceiver1 = new AdvancedReceiver();
		advancedReceiver1.receive(child1);
		
		Child child2 = new Child();
		Receiver advancedReceiver2 = new AdvancedReceiver();
		advancedReceiver2.receive(child2);
	}
}

что отпринтуется на выходе?

PS: даже не зная явы совсем, ошибся только в одном месте (не заметил полиморф :) )

Deleted

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

Deleted
()
Ответ на: комментарий от Deleted

Явы не знаю, но думаю что так

AdvancedReceiver
Child
AdvancedReceiver
Child

Я не знаю, по каким правилам там что в яве работает, но сдаётся мне, что будет оно так. Делаем же двух АдванседРесивров и двух Чайлдов (и пофигу, что в первого ресивера первый чайлд суём приведенный к паренту).

yoghurt ★★★★★
()

Яву толком не знаю, но по аналогии с++ должно быть так:

Receiver
Parent
AdvancedReceiver
Child

сейчас проверю

hunt
()

А кстати, в этой вашей яве все методы изначально виртуальные, или надо явно указывать?

Если второе, то я слил

yoghurt ★★★★★
()
Ответ на: комментарий от svu

Неужели что-то надо объяснять? Надо просто подумать, как жвм будет выбирать методы. Из каких соображений - на этапе компиляции и в рантайме.

svu ★★★★★
()

А победителям что, пиво? Если да, то мне Гиннеса холодного, пожалуйста. Две

yoghurt ★★★★★
()
Ответ на: комментарий от svu

Сначала она выберет Receiver.receive(Parent) Потому что параметр указан с типом Parent (child1), компилятор сгеренит код по поиску функции с таким параметром, жвм посмотрит на все виртуальные методы с таким параметром и найдет единственный.

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

Вернемся в мейн. Компилятор(!!) не знает, что у кого-то из подклассов Receivers есть метод с параметром Child, но зато знает, что у базового класса есть метод с классом Parent - поэтому сгенерит код, который будет искать виртуальный метод с параметром Parent. Опять же, жвм найдет Receiver.receive(Parent) и далее по тексту.

svu ★★★★★
()
Ответ на: комментарий от yoghurt

Ага, ошибся. Надо Страуструпа перечитывать

int main()
{
	Parent* child1 = new Child;
	AdvancedReceiver* advancedReceiver1 = new AdvancedReceiver;
	advancedReceiver1->receive(child1); // 37 line
	
	Child* child2 = new Child
	Receiver* advancedReceiver2 = new AdvancedReceiver;
	advancedReceiver2->receive(child2);
	
	return 0;
}
hunt@zeus:~/temp$ g++ test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:37: error: invalid conversion from ‘Parent*’ to ‘Child*’
test.cpp:37: error:   initializing argument 1 of ‘void AdvancedReceiver::receive(Child*)’

только dynamic_cast поможет

hunt
()
Ответ на: комментарий от svu

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

svu ★★★★★
()
Ответ на: комментарий от vga

Я заметил, но думал, что раз уж аргументы их есть один наследник другого, всё разрулится должным образом :)

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Нет, это ж ява, со своими правилами. Вот если поправить аргумент во втором receive на Parent - то все будет, как ты написал.

vga ★★
()

Ну что ж, единственный победитель - svu :) хоть и не с первого раза, но все же поправился ;). Я собственно также, сначала не заметил что метод recieve полиморфен, т.е. в потомке два метода с этим названием, но с разными параметрами. Только это меня и сбило с толку, а то что всегда будет child я сразу определил. Собственно у меня также, правильный резалт со второй попытки :)

Deleted
()
Ответ на: Явы не знаю, но думаю что так от yoghurt

>AdvancedReceiver

Child
AdvancedReceiver
Child

Я не знаю, по каким правилам там что в яве работает

я ровно также ответил первый раз, когда мне показали задачку. И тут нет ничего особенного... классический ООП. Я же даже в самом начале написал, что сам не заметил полиморф, разве это не было подсказкой? ;)

Deleted
()
Ответ на: комментарий от SSZB

>Это что, печальная история об ООП и перегрузке методов???

просто проверить себя на знание ООП

Deleted
()
Ответ на: комментарий от yoghurt

>скорее о jvm и типизации

при чем тут jvm? покажи хоть одну строчку где бы было что-то отличительное от общих принципов ООП?

Deleted
()
Ответ на: комментарий от yoghurt

этот короткий пример, кстати, максимально захватывает общие принципы ООП - наследование, перегрузка, полиморфизм. Так что для студентов очень даже наглядный пример.

Deleted
()
Ответ на: комментарий от svu

яву не знаю, прогу не компилял, коменты не читал, но я угадал ))

antony986
()
Ответ на: комментарий от Deleted

"OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things"

В приведеннём коде есть, пожалуй, только последнее.

yoghurt ★★★★★
()
Ответ на: комментарий от Deleted

На мой скромный взгляд уж что что, а перегрузка к ООП имеет весьма и весьма посредственное значение

yoghurt ★★★★★
()
Ответ на: комментарий от Deleted

ну ну. Этот пример наглядно демонстрирует только убогое жабское статическое недоооп.

Вот Ъ ООП:

(defclass parent () ())

(defclass child (parent) ())

(defclass receiver () ())

(defclass advanced-receiver (receiver) ())

(defgeneric receive (receiver object))

(defmethod receive ((receiver receiver) (object parent))
  (write-line "Receiver && Parent"))

(defmethod receive ((receiver advanced-receiver) (object child))
  (write-line "Advanced receiver && Child"))

(defun main ()
  (let ((parent (make-instance 'parent))
        (child (make-instance 'child))
        (receiver (make-instance 'receiver))
        (advanced-receiver (make-instance 'advanced-receiver)))
    (receive receiver          parent)
    (receive receiver          child)
    (receive advanced-receiver parent)
    (receive advanced-receiver child)
    T))

;;(main) =>
;; Receiver && Parent
;; Receiver && Parent
;; Receiver && Parent
;; Advanced receiver && Child

Love5an
()
Ответ на: комментарий от yoghurt

согласен, с перегрузкой малость перегнул, но она весьма сильно эксплуатируется в ООП.

Deleted
()

Ну вроде

Receiver Child Receiver Child

Legioner ★★★★★
()

жаву не знаю, но

Receiver (т.к. вызывается receive(Parent p), унаследованный от Receiver)
Child (т.к. передается на самом деле объект, созданный как Child)
AdvancedReceiver (т.к. вызывается receive(Child c), созданный уже в AdvancedReceiver)
Child (см.п.2)

xydo ★★
()
Ответ на: комментарий от xydo

вру. не заметил «Receiver advancedReceiver2». тогда, да, Receiver-Child-Receiver-Child. впрочем, svu уже и так всё по полочкам разложил.

xydo ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.