Являются ли виртуальные методы для методов, которые не создаются до времени выполнения? - PullRequest
0 голосов
/ 23 ноября 2011

У меня возникли проблемы с пониманием назначения виртуального метода в C ++.Должен ли метод быть виртуальным, если его объект не создан во время компиляции?Например, если вы должны были выбрать сельскохозяйственное животное во время выполнения, все методы животного должны были бы быть виртуальными, потому что пока пользователь не выберет один, вы не знаете, будет ли он создан или нет.Пожалуйста, поправьте меня, если я ошибаюсь.

Ответы [ 5 ]

7 голосов
/ 23 ноября 2011

Нет, это совершенно неверно. Метод должен быть виртуальным, если метод должен быть выбран на основе type объекта, а type не известен во время компиляции. Если ваш код выглядит так:

Animal *x;
if(y==2)
{
    x = new Animal();
    x->DoSomething();
}

Компилятор знает во время выполнения, что тип x - «Животное». Таким образом, он знает, какую версию DoSomething вызывать. Но посмотрите на этот код:

Animal *x;
if(y==1) x=new Zebra();
else if (y==2) x=GetSomeAnimal();
else x=new Giraffe();
x->DoSomething();

Здесь тип x не известен во время компиляции. Это может быть Зебра, Жираф или Любой тип Животных, которые возвращает функция GetSomeAnimal. Нет никакого способа узнать, должен ли вызов DoSomething вызывать Zebra::DoSomething, Giraffe::DoSomething или что-то еще полностью. Так что Animal::DoSomething должно быть виртуальным.

И чтобы показать, что это не имеет ничего общего с тем, что будет создано, рассмотрим следующее:

void MyFunction(Animal &x)
{
    x.DoSomething();
}

void MyOtherFunction(int x)
{
   Giraffe g;
   Zebra z;
   if(x==2) MyFunction(g);
      else MyFunction(f);
}

Здесь совершенно ясно, что будет создан один Giraffe и один Zebra. Но если Animal::DoSomething не является виртуальным, MyFunction будет вызывать Animal::DoSomething оба раза вместо Giraffe::DoSomething на Жирафе и Zebra::DoSomething на Зебре. (Конечно, если это то, что вы хотите , не делайте метод виртуальным.)

0 голосов
/ 23 ноября 2011

Если у вас есть этот код:

Animal * a = new Pig();

Указатель a имеет статический тип Animal и динамический тип Pig.

Теперь допустим, мы звоним

a->MakeASound();

Если MakeASound является виртуальным, то вызывается метод MakeASound динамического типа (Pig).

Если это не так, вызывается MakeASound статического типа (Animal) независимо от того, перезаписывает ли Pig метод MakeASound или нет.

0 голосов
/ 23 ноября 2011

Одна из более важных целей виртуальных функций - разрешить старому коду вызывать новый код .

Учтите это.Функция принимает в качестве параметра объект Car.Предположим, что он выполняет такие функции, как test_drive (), refel (), calc_ability (), getStoppingDistance () и т. Д. Все эти методы зависят от типа автомобиля, который вы проезжаете.

Но новые автомобили появляются каждый год.Теперь, в реальном мире, мы бы просто импортировали файл XML, который содержал свойства, которые составляют все автомобили.Но предположим, ради аргумента, что мы должны были сделать это статически: каждый раз, когда мы узнавали о новых автомобилях, нам приходилось перестраивать всю нашу программу.Если бы наша программа была огромной, это было бы очень неудобно.В некотором смысле, мы вызываем одни и те же функции, но в некотором смысле это не так, поскольку тип объекта меняется.Почему мы должны перекомпилировать?

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

0 голосов
/ 23 ноября 2011

Ну, virtual - это то, что встроено в C ++ для поддержки OOD полиморфизма (в частности, времени выполнения или динамического единицы).

Когда вы хотите, чтобы разные объекты одного типа (Animal) вели себя по-разному (getProduceName() возвращает «свинину», «говядину», «яйцо» или ...) в зависимости от контекста (является ли Animal на самом деле Pig или Cow, или Chicken, или ...) вы делаете это поведение / функцию virtual.

Обычно хороший OOD будет иметь хорошее разделение интерфейса / реализации. В C ++ это реализуется с использованием наследования вместе с abstract классами / методами.

Таким образом, на самом деле, когда вы делаете getProduceName() полиморфный / virtual, вы на самом деле пытаетесь извлечь интерфейс (Animal) из различных реализаций (Pig или Cow или Chicken или ...) чтобы защитить ваш клиентский код от различных реализаций. Таким образом, если вам нужно поддерживать новую реализацию, вам не нужно менять клиентский код, пока он придерживается интерфейса Animal.

Итак, чтобы ответить на вопрос: Должен ли метод быть виртуальным, если его объект не создан во время компиляции?

Является ли метод виртуальным или нет, не зависит от того, когда был создан объект (компиляция / время выполнения). Это зависит от того, как вы хотите разработать приложение. Создание функции virtual поможет вам извлечь интерфейс из различных реализаций. Если определенная функция (getOwnerName()) имеет одинаковую реализацию во всех реализующих классах ({return ownerName;}), ее не нужно делать виртуальной.

PS: ИМХО полиморфизм - это побочный продукт хорошего OOD, вы не разрабатываете свои классы для реализации «полиморфизма времени выполнения», а затем демонстрируете полиморфизм времени исполнения, когда у вас хороший дизайн OO.

0 голосов
/ 23 ноября 2011

Читайте о назначении виртуальных методов здесь .Я также рекомендую вам взглянуть на «Объектно-ориентированное программирование в ANSI C» книгу.

...