Войти
ПрограммированиеФорумОбщее

Полиморфизм с++ Что не так с этим кодом?

Страницы: 1 2 3 4 5 6 Следующая »
#0
6:31, 3 фев. 2012

Что вообще происходит с этим кодом?

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

struct Base {  virtual Base* clone() const = 0; };

struct Derived : public Base
{
    Derived* clone() const    {     std::cout<<"Создаю Derived\n";      Test();      return new Derived(*this);       }
    void Test() { std::cout<<"Test\n"; }
};


int main()
{
  Base* ptr = new Derived;
  ptr->clone(); //вывод: Создаю Derived
}


И ещё такой вопрос: Если я действительно могу из базового класса запустить данный метод предка, то почему тогда я не могу сделать вот так:

struct Base {  virtual Base* clone() = 0; };

struct Derived : public Base
{
    Derived* clone() 
    {
        std::cout<<"Создаю Derived\n"; Test(); 
        Derived* ptr = new Derived;  return ptr;
    }
    void Test() const { std::cout<<"Test\n"; }
};

int main()
{
  Base* ptr = new Derived;
  (ptr->clone())->Test();      //: error C2039: Test: не является членом "Base"
}

Ведь результатом  ptr->clone() должен быть реальный объект типа Derived!
То есть, метод Test() я уже запускаю для Derived, а не для базы!


#1
7:08, 3 фев. 2012

Kartonagnick
> Ведь результатом ptr->clone() должен быть реальный объект типа Derived!
У тебя же указано в классе Base что должен возвращать метод clone, в той самой строчке ты работаешь именно с Base, он и возвращает Base *.

#2
7:18, 3 фев. 2012


Жора Монтировка
> У тебя же указано в классе Base что должен возвращать метод clone, в той самой
> строчке ты работаешь именно с Base, он и возвращает Base *.

У меня же указанно в методе Derived, что возвращается Derived, и запускается именно этот метод. Почему тогда возвращается Base* ?

#3
8:04, 3 фев. 2012

тип переменной ptr - Base*, информация о том, что по указателю, на самом деле, сидит экземпляр типа-потомка Derived, утеряна. Компилятор "не знает" об этом, поэтому и сообщает об ошибке компиляции.

#4
8:12, 3 фев. 2012

Kartonagnick
Нужно привести ptr к типу Derived.
Тогда компилятор увидит метод Test и сможет его исполнить.
По первому вопросу создаётся объект Derived, но ссылка по-прежнему возвращается на его предка.
Учи ООП.

#5
8:37, 3 фев. 2012

Rhob Slein
> тип переменной ptr - Base*, информация о том, что по указателю, на самом деле,
> сидит экземпляр типа-потомка Derived, утеряна. Компилятор "не знает" об этом,
> поэтому и сообщает об ошибке компиляции.

Почему он не различает разницу в сигнатурах функций?

dyvniy
> По первому вопросу создаётся объект Derived, [b]но ссылка по-прежнему возвращается на его предка.[/b]
Почему? Если сигнатура метода потомка должна возвращать потомка?

dyvniy
> Учи ООП.

Слющай, дарагой! Механика с++ рассматривается, да? Виртуальный полиморфизм с++ рассматривается, да дарагой? Сферический ООП тут вапще не причем, все понял дарагой?

#6
8:57, 3 фев. 2012

Kartonagnick
> Почему он не различает разницу в сигнатурах функций?
  А что такое сигнатура в С++ ты хотя бы знаешь? Она тип возвращаемого значения вообще не учитывает.

> Почему? Если сигнатура метода потомка должна возвращать потомка?
  ptr это указатель на Base, так какого фига ты хочешь, чтобы через него вызывался Test, которого в Base нет?

#7
9:05, 3 фев. 2012

Zefick
> А что такое сигнатура в С++ ты хотя бы знаешь? Она тип возвращаемого значения
> вообще не учитывает.

А.. ну да, точно. Но тем не менее, функция, которая возвращает другое значение, это уже совсем другая функция. Разве не?

Zefick
> ptr это указатель на Base, так какого фига ты хочешь, чтобы через него
> вызывался Test, которого в Base нет?

(ptr->clone())->Test();

Сначала вычисляется то, что в скобочках:

Derived::clone(); имеет тип возвращаемого значения Derived*. Результат выражения - указатель на Derived

Потом, уже к этому указателю будет применен метод Test

(указатель на Derived)->Test();

Но этого не происходит. Поэтому два вопроса:
1. Почему вообще запускается функция, которая по возвращаемому значению отличается.
2. Почему по указателю на Derived, учитывая что живет там действительно Derived не запускается метод Derived?

#8
10:03, 3 фев. 2012

Kartonagnick
> 1. Почему вообще запускается функция, которая по возвращаемому значению
> отличается.
  Потому что стандарт это разрешает.

> 2. Почему по указателю на Derived, учитывая что живет там действительно Derived
> не запускается метод Derived?
  Потому что в языке такие правила. Ты обращаешься к Base::clone, получаешь Base *. Всё.

#9
10:15, 3 фев. 2012

1. Тип возвращаемого значения не входит в сигнатуру, исполняющая система на нижнем уровне проблем по совмещению не испытывает.
2. Такой вот прием, базовый объект возвращает ссылку на базовый, а наследник на наследника, специально разрешен, синтаксический анализатор потому и пропускает.
3. Работаешь ты с той ссылкой, которую сам задекларировал. Сказал бы что работаешь с Derived, был бы доступен Test. Объект правильный, Derived, но синтаксический анализатор об этом не знает.

#10
10:16, 3 фев. 2012

Zefick
> Потому что в языке такие правила. Ты обращаешься к Base::clone, получаешь Base
> *. Всё.

В общем, читанул "convariant return types". Действительно. Сделали специально для того, что бы потомок через базовый указатель смог создать другого потомка.
Но общаться с ним можно только через интерфейс базового класса.

Но тогда такой вопрос: существует ли способ, как обойти это ограничение, и получить доступ к методам потомка?
Не делая при этом явного приведения типов

#11
10:20, 3 фев. 2012

Kartonagnick
>А.. ну да, точно. Но тем не менее, функция, которая возвращает другое значение, это уже совсем другая функция. Разве не?
В С++ функции различаются только передаваемыми параметрами, хотя некоторые компиляторы возможно будут ругаться, если возвращаемое значение различается.

>Сначала вычисляется то, что в скобочках:
При компиляции компилятор увидит что вызван метод clone, который возвращает указатель на Base, думаешь он догадается, что этот указатель будет указывать на Derived?

>Результат выражения - указатель на Derived
Результат выражения - указатель на Base, указывающий на объект Derived, а это не тоже самое.

#12
10:26, 3 фев. 2012

nes
> Результат выражения - указатель на Base, указывающий на объект Derived, а это
> не тоже самое.

Нет. Формально там Derived*. Но компилятор почему то парсит в Base*
Типа правила языка такие на этот случай предусмотрены.

((Derrived*)(ptr->clone()))->Test(); //вот так можно.

Как сделать тоже самое, ток без явного приведения?

#13
10:36, 3 фев. 2012

1. метод Test перенести в Base
2. делать dynamic_cast

Если ты собрался работать с интерфейсом, работай с интерфейсом, а не пытайся вылезти за его пределы.

#14
10:36, 3 фев. 2012

Kartonagnick
> Нет. Формально там Derived*. Но компилятор почему то парсит в Base*
> Типа правила языка такие на этот случай предусмотрены.

что ты упираешься ?

какой тип возращается у Base::clone() ?

Страницы: 1 2 3 4 5 6 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.