Ответы:
Из Виртуальной функции Википедии ...
В объектно-ориентированном программировании в таких языках, как C ++ и Object Pascal, виртуальная функция или виртуальный метод - это наследуемая и переопределяемая функция или метод, для которых облегчается динамическая диспетчеризация. Эта концепция является важной частью (полиморфизма во время выполнения) части объектно-ориентированного программирования (ООП). Короче говоря, виртуальная функция определяет целевую функцию, которая будет выполняться, но цель может быть неизвестна во время компиляции.
В отличие от не виртуальной функции, когда виртуальная функция переопределяется, наиболее производная версия используется на всех уровнях иерархии классов, а не только на уровне, на котором она была создана. Следовательно, если один метод базового класса вызывает виртуальный метод, версия, определенная в производном классе, будет использоваться вместо версии, определенной в базовом классе.
Это в отличие от не виртуальных функций, которые все еще могут быть переопределены в производном классе, но «новая» версия будет использоваться только производным классом и ниже, но не изменит функциональность базового класса вообще.
в то время как..
Чистая виртуальная функция или чисто виртуальный метод - это виртуальная функция, которая должна быть реализована производным классом, если производный класс не является абстрактным.
Когда существует чисто виртуальный метод, класс является «абстрактным» и не может быть создан самостоятельно. Вместо этого должен использоваться производный класс, который реализует чисто виртуальный метод (ы). Чисто виртуальный вообще не определен в базовом классе, поэтому производный класс должен его определять, или этот производный класс также является абстрактным и не может быть создан. Только класс, который не имеет абстрактных методов, может быть создан.
Виртуальный предоставляет способ переопределить функциональность базового класса, а чисто виртуальный требует этого.
pure
ключевое слово, но Bell Labs собиралась выпустить крупную версию C ++, и его менеджер не допустил бы этого на этой поздней стадии. Добавление ключевых слов это большое дело.
Я хотел бы прокомментировать определение виртуального Википедии, как повторяется здесь. [На момент написания этого ответа] Википедия определила виртуальный метод как метод, который можно переопределить в подклассах. [К счастью, с тех пор Википедия была отредактирована, и теперь она объясняет это правильно.] Это неверно: любой метод, не только виртуальный, может быть переопределен в подклассах. Что делает виртуальный, так это дает вам полиморфизм, то есть способность выбирать во время выполнения наиболее производное переопределение метода .
Рассмотрим следующий код:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
Каков вывод этой программы?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Производный переопределяет каждый метод Base: не только виртуальный, но и не виртуальный.
Мы видим, что когда у вас есть Base-pointer-to-Derived (bDerived), вызов NonVirtual вызывает реализацию базового класса. Это решается во время компиляции: компилятор видит, что bDerived - это Base *, что NonVirtual не является виртуальным, поэтому он выполняет разрешение для класса Base.
Однако вызов Virtual вызывает реализацию класса Derived. Из-за ключевого слова virtual выбор метода происходит во время выполнения , а не во время компиляции. Во время компиляции происходит то, что компилятор видит, что это Base *, и что он вызывает виртуальный метод, поэтому он вставляет вызов vtable вместо класса Base. Этот vtable создается во время выполнения, следовательно, разрешение во время выполнения переопределяется по большинству производных.
Надеюсь, это не слишком запутанно. Короче говоря, любой метод может быть переопределен, но только виртуальные методы дают вам полиморфизм, то есть выбор во время выполнения наиболее производного переопределения. На практике, однако, переопределение не виртуального метода считается плохой практикой и используется редко, поэтому многие люди (включая тех, кто написал эту статью в Википедии) считают, что только виртуальные методы могут быть переопределены.
Derived*
с теми же вызовами функций, чтобы увести точку домой. В противном случае отличный ответ
Ключевое слово virtual дает C ++ возможность поддерживать полиморфизм. Когда у вас есть указатель на объект некоторого класса, такой как:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
В этом (глупом) примере функция GetNumberOfLegs () возвращает соответствующее число на основе класса объекта, для которого она вызывается.
Теперь рассмотрим функцию SomeFunction. Неважно, какой тип животного объекта передается ему, если он получен из Animal. Компилятор автоматически преобразует любой производный от Animal класс в Animal, поскольку он является базовым классом.
Если мы сделаем это:
Duck d;
SomeFunction(&d);
это вывело бы '2'. Если мы сделаем это:
Horse h;
SomeFunction(&h);
это вывело бы '4'. Мы не можем сделать это:
Animal a;
SomeFunction(&a);
потому что он не будет компилироваться из-за того, что виртуальная функция GetNumberOfLegs () является чистой, что означает, что она должна быть реализована путем получения классов (подклассов).
Чистые виртуальные функции в основном используются для определения:
а) абстрактные классы
Это базовые классы, где вы должны извлечь их, а затем реализовать чисто виртуальные функции.
б) интерфейсы
Это «пустые» классы, где все функции являются чисто виртуальными, и, следовательно, вы должны получить и затем реализовать все функции.
В классе C ++, virtual - это ключевое слово, которое обозначает, что метод может быть переопределен (т.е. реализован) подклассом. Например:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
В этом случае подкласс может переопределить функцию initShape для выполнения некоторой специализированной работы:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Термин « чисто виртуальный» относится к виртуальным функциям, которые должны быть реализованы подклассом и не были реализованы базовым классом. Вы определяете метод как чисто виртуальный, используя ключевое слово virtual и добавляя = 0 в конце объявления метода.
Итак, если вы хотите сделать Shape :: initShape чисто виртуальным, вы должны сделать следующее:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Добавляя чистый виртуальный метод в ваш класс, вы делаете класс абстрактным базовым классом, который очень удобен для отделения интерфейсов от реализации.
m_name
. Что m_
значит?
«Виртуальный» означает, что метод может быть переопределен в подклассах, но имеет непосредственную реализацию в базовом классе. «Чистый виртуальный» означает, что это виртуальный метод без прямой реализации. Такой метод должен быть переопределен хотя бы один раз в иерархии наследования - если у класса есть какие-либо нереализованные виртуальные методы, объекты этого класса не могут быть созданы, и компиляция завершится неудачно.
@quark указывает, что чисто виртуальные методы могут иметь реализацию, но поскольку чисто виртуальные методы должны быть переопределены, реализация по умолчанию не может быть вызвана напрямую. Вот пример чисто виртуального метода по умолчанию:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
Согласно комментариям, неудача компиляции зависит от компилятора. По крайней мере, в GCC 4.3.3 он не будет компилироваться:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Вывод:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
Как работает виртуальное ключевое слово?
Предположим, что человек является базовым классом, индиец происходит от человека.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Объявление do_work () как виртуального просто означает, что do_work () для вызова будет определено ТОЛЬКО во время выполнения.
Предположим, я делаю,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Если virtual не используется, то же самое статически определяется или статически связывается компилятором, в зависимости от того, какой объект вызывается. Так что если объект Man вызывает do_work (), то do_work () Man называется ДАЖЕ, ЧТО ЭТО УКАЗЫВАЕТ НА ИНДИЙСКИЙ ОБЪЕКТ
Я считаю, что ответ с наибольшим количеством голосов вводит в заблуждение - любой метод, виртуальный или нет, может иметь переопределенную реализацию в производном классе. При конкретной ссылке на C ++ правильной разницей является привязка времени выполнения (когда используется виртуальная) и время компиляции (когда виртуальная не используется, но метод переопределен, а базовый указатель указывает на производный объект), привязка связанных функций.
Кажется, есть еще один вводящий в заблуждение комментарий, который гласит:
«Джастин,« чисто виртуальный »- это просто термин (не ключевое слово, см. Мой ответ ниже), используемый для обозначения« эта функция не может быть реализована базовым классом ».
ЭТО НЕ ВЕРНО! Чисто виртуальные функции также могут иметь тело и могут быть реализованы! Правда в том, что чисто виртуальную функцию абстрактного класса можно вызывать статически! Два очень хороших автора - Бьярн Страуструп и Стэн Липпман ... потому что они написали язык.
Виртуальная функция - это функция-член, которая объявлена в базовом классе и переопределена производным классом. Виртуальные функции являются иерархическими в порядке наследования. Когда производный класс не переопределяет виртуальную функцию, используется функция, определенная в его базовом классе.
Чистая виртуальная функция - это та, которая не содержит определения относительно базового класса. У него нет реализации в базовом классе. Любой производный класс должен переопределить эту функцию.
Simula, C ++ и C #, которые по умолчанию используют статическое связывание методов, программист может указать, что конкретные методы должны использовать динамическое связывание, пометив их как виртуальные. Динамическое связывание методов является центральным в объектно-ориентированном программировании.
Объектно-ориентированное программирование требует трех основных понятий: инкапсуляция, наследование и динамическое связывание методов.
Инкапсуляция позволяет скрыть детали реализации абстракции за простым интерфейсом.
Наследование позволяет определить новую абстракцию как расширение или уточнение некоторой существующей абстракции, автоматически получая некоторые или все ее характеристики.
Динамическое связывание метода позволяет новой абстракции отображать свое новое поведение, даже если оно используется в контексте, который ожидает старую абстракцию.
Виртуальные методы МОГУТ быть переопределены производными классами, но нуждаются в реализации в базовом классе (тот, который будет переопределен)
Чистые виртуальные методы не имеют реализации базового класса. Они должны быть определены производными классами. (Так что технически переопределено не правильный термин, потому что нечего переопределять).
Virtual соответствует стандартному поведению Java, когда производный класс переопределяет метод базового класса.
Чисто виртуальные методы соответствуют поведению абстрактных методов внутри абстрактных классов. И класс, который содержит только чистые виртуальные методы и константы, будет cpp-pendant для интерфейса.
Чистая виртуальная функция
попробуй этот код
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()=0;
};
class anotherClass:aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"hellow World";
}
};
int main()
{
//aClassWithPureVirtualFunction virtualObject;
/*
This not possible to create object of a class that contain pure virtual function
*/
anotherClass object;
object.sayHellow();
}
В классе anotherClass удалите функцию sayHellow и запустите код. вы получите ошибку! Потому что, когда класс содержит чисто виртуальную функцию, из этого класса невозможно создать объект, и он наследуется, тогда его производный класс должен реализовать эту функцию.
Виртуальная функция
попробуй другой код
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()
{
cout<<"from base\n";
}
};
class anotherClass:public aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"from derived \n";
}
};
int main()
{
aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
baseObject->sayHellow();///call base one
baseObject=new anotherClass;
baseObject->sayHellow();////call the derived one!
}
Здесь функция sayHellow помечена как виртуальная в базовом классе. Это говорит о компиляторе, который пытается найти функцию в производном классе и реализовать функцию. Если она не найдена, выполнить базовую. Спасибо
«Виртуальная функция или виртуальный метод - это функция или метод, поведение которых может быть переопределено в наследующем классе функцией с такой же сигнатурой» - википедия
Это не очень хорошее объяснение для виртуальных функций. Потому что, даже если член не является виртуальным, наследующие классы могут переопределить его. Вы можете попробовать и увидеть это сами.
Разница проявляется, когда функция принимает базовый класс в качестве параметра. Когда вы задаете наследующий класс в качестве входных данных, эта функция использует реализацию переопределенной функции базового класса. Однако, если эта функция является виртуальной, она использует ту, которая реализована в производном классе.
Виртуальные функции должны иметь определение в базовом классе, а также в производном классе, но не обязательно, например, функция ToString () или toString () является виртуальной, чтобы вы могли предоставить собственную реализацию, переопределив ее в определяемом пользователем классе (ах).
Виртуальные функции объявлены и определены в обычном классе.
Чистая виртуальная функция должна быть объявлена с окончанием "= 0", и она может быть объявлена только в абстрактном классе.
Абстрактный класс, имеющий чисто виртуальную функцию (и), не может иметь определения (ей) этих чисто виртуальных функций, поэтому он подразумевает, что реализация должна быть обеспечена в классе (ах), который получен из этого абстрактного класса.