Відповіді:
З віртуальної функції Вікіпедії ...
У об'єктно-орієнтованому програмуванні на таких мовах, як C ++ та Object Pascal, віртуальна функція або віртуальний метод - це успадкована і перезаписувана функція або метод, для якого сприяє динамічне відправлення. Ця концепція є важливою частиною (під час виконання) поліморфізму частини об'єктно-орієнтованого програмування (ООП). Коротше кажучи, віртуальна функція визначає цільову функцію, яка повинна виконуватися, але ціль може бути невідома під час компіляції.
На відміну від невіртуальної функції, коли віртуальну функцію переосмислено, найпохідніша версія використовується на всіх рівнях ієрархії класів, а не лише на тому рівні, на якому вона була створена. Отже, якщо один метод базового класу викликає віртуальний метод, замість версії, визначеної в базовому класі, буде використана версія, визначена у похідному класі.
Це на відміну від невіртуальних функцій, які все-таки можуть бути замінені у похідному класі, але "нова" версія буде використовуватися лише похідним класом та нижче, але взагалі не змінить функціональність базового класу.
тоді як ..
Чиста віртуальна функція або чистий віртуальний метод - це віртуальна функція, яку потрібно реалізувати похідним класом, якщо похідний клас не є абстрактним.
Коли існує чистий віртуальний метод, клас є "абстрактним" і не може бути ідентифікований самостійно. Натомість повинен бути використаний похідний клас, який реалізує чисто-віртуальні методи. Чисто-віртуальний взагалі не визначений у базовому класі, тому похідний клас повинен визначати його, або цей похідний клас також абстрактний і не може бути ідентифікований. Тільки клас, який не має абстрактних методів, може бути екземпляром.
Віртуальний забезпечує спосіб перекриття функціональності базового класу, а чисто-віртуальний цього вимагає .
pure
ключове слово, але Bell Labs збирається зробити великий реліз C ++, і його менеджер не дозволить цього на пізньому етапі. Додавання ключових слів - велика справа.
Я хотів би прокоментувати визначення віртуальної Вікіпедії, яке повторило декілька тут. [На момент написання цієї відповіді] Вікіпедія визначила віртуальний метод як той, який можна перекрити в підкласах. [На щастя, Wikipedia редагується з цього часу, і тепер це правильно пояснюється.] Це неправильно: будь-який метод, не лише віртуальний, може бути замінений у підкласах. Що віртуальне - це надати вам поліморфізм, тобто можливість вибору під час виконання найбільш перетвореного методу .
Розглянемо наступний код:
#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 викликає реалізацію класу Base. Це вирішується під час компіляції: компілятор бачить, що bDerived - це Base *, що NonVirtual не є віртуальним, тому робить роздільну здатність для класу Base.
Однак виклик Virtual викликає реалізацію класу похідних. Через віртуальне ключове слово, вибір методу відбувається під час виконання , а не під час компіляції. Що відбувається тут під час компіляції, це те, що компілятор бачить, що це Base * і що він викликає віртуальний метод, тому він вставляє виклик в vtable замість класу Base. Цей vtable інстанціюється під час виконання, отже, роздільна здатність часу для перетворення найбільшої кількості.
Я сподіваюся, що це було не надто заплутано. Коротше кажучи, будь-який метод може бути відмінений, але лише віртуальні методи дають вам поліморфізм, тобто підбір часу найбільшої похідної зміни. На практиці, однак, перекриття невіртуального методу вважається поганою практикою і використовується рідко, тому багато людей (включаючи тих, хто написав цю статтю у Вікіпедії) вважають, що можна відмінити лише віртуальні методи.
Derived*
дзвінки з тією ж функцією, щоб керувати точкою додому. Інакше чудова відповідь
Віртуальне ключове слово надає С ++ свою здатність підтримувати поліморфізм. Коли у вас є вказівник на об’єкт деякого класу, такий як:
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 тварині, оскільки це базовий клас.
Якщо ми це зробимо:
Duck d;
SomeFunction(&d);
він буде виводити "2". Якщо ми це зробимо:
Horse h;
SomeFunction(&h);
він буде виводити "4". Ми не можемо цього зробити:
Animal a;
SomeFunction(&a);
тому що вона не буде компілюватися через чисту віртуальну функцію GetNumberOfLegs (), що означає, що вона повинна бути реалізована шляхом отримання класів (підкласів).
Чисті віртуальні функції в основному використовуються для визначення:
а) абстрактні заняття
Це базові класи, де ви маєте виходити з них, а потім реалізовувати чисті віртуальні функції.
б) інтерфейси
Це "порожні" класи, де всі функції є чистими віртуальними, отже, ви повинні отримати та реалізувати всі функції.
У класі C ++ віртуальний - це ключове слово, яке позначає це, метод може бути замінений (тобто реалізований) підкласом. Наприклад:
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");
}
}
Термін чистий віртуальний відноситься до віртуальних функцій, які потрібно реалізувати підкласом і не були реалізовані базовим класом. Ви позначаєте метод як чистий віртуальний, використовуючи віртуальне ключове слово та додаючи a = 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.
Якщо віртуальний не використовується, те саме визначається статично або статично пов'язане компілятором, залежно від того, який об'єкт викликає. Отже, якщо об’єкт Людини викликає do_work (), робота людини () називається НАДІЙСЬКІ, ЩО ВИНАЄТЬСЯ НА ІНДІЙСЬКИЙ ОБ'ЄКТ
Я вважаю, що відповідь, що голосує вгорі, вводить в оману - будь-який метод, незалежно від того, віртуальний може мати переохоплену реалізацію у похідному класі При конкретному посиланні на C ++ правильною різницею є час виконання (коли використовується віртуальний) прив'язка та час компіляції (коли віртуальний не використовується, але метод переосмислений і базовий покажчик вказується на похідний об'єкт) прив'язка пов'язаних функцій.
Здається, є ще один оманливий коментар, який говорить:
"Джастін," чистий віртуальний "- це лише термін (не ключове слово, див. Мою відповідь нижче), який використовується для означання" ця функція не може бути реалізована базовим класом ".
ЦЕ НЕПРАВИЛЬНО! Чисто віртуальні функції також можуть мати тіло і МОЖУТЬ ВПРОВАДЖУВАТИ! Правда полягає в тому, що чисту віртуальну функцію абстрактного класу можна назвати статично! Два дуже хороших автори - Б'ярн Струструп і Стен Ліппман .... тому що вони написали мову.
Віртуальна функція - це функція-член, яка оголошується в базовому класі і переосмислюється похідним класом. Віртуальна функція є ієрархічною в порядку спадкування. Коли похідний клас не перекриває віртуальну функцію, використовується функція, визначена в її базовому класі.
Чиста віртуальна функція - це та функція, яка не містить визначення відносно базового класу. Він не має реалізації в базовому класі. Будь-який похідний клас повинен перекрити цю функцію.
Simula, C ++ і C #, які використовують статичний метод прив'язки за замовчуванням, програміст може вказати, що конкретні методи повинні використовувати динамічне прив'язування, позначаючи їх як віртуальні. Динамічний метод прив'язки є основним для об'єктно-орієнтованого програмування.
Об'єктно-орієнтоване програмування вимагає трьох основних понять: інкапсуляція, успадкування та прив'язка динамічного методу.
Інкапсуляція дозволяє приховувати деталі реалізації абстракції за простим інтерфейсом.
Спадкування дозволяє нову абстракцію визначати як розширення або уточнення деякої існуючої абстракції, отримуючи деякі або всі її характеристики автоматично.
Динамічний метод прив'язки дозволяє новій абстракції відображати свою нову поведінку, навіть коли вона використовується в контексті, який очікує стару абстракцію.
Віртуальними методами МОЖЕ бути замінено шляхом отримання класів, але потрібна реалізація в базовому класі (той, який буде переосмислений)
Чисті віртуальні методи не мають реалізації базового класу. Їх потрібно визначити за похідними класами. (Отже, технічно переоцінений не є правильним терміном, тому що не можна нічого переосмислювати).
Віртуальна відповідає поведінці Java за замовчуванням, коли похідний клас замінює метод базового класу.
Чисті віртуальні методи відповідають поведінці абстрактних методів у межах абстрактних класів. І клас, який містить лише чисті віртуальні методи та константи, був би cpp-кулон інтерфейсу.
Чиста віртуальна функція
спробуйте цей код
#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();
}
У класі elseClass видаліть функцію 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 позначена як віртуальна в базовому класі. Скажіть компілятор, який спробує виконати пошук функції у похідному класі та реалізувати функцію. Якщо не знайдено, то виконайте базовий. Дякую
"Віртуальна функція або віртуальний метод - це функція або метод, поведінку якого можна замінити в межах спадкового класу функцією з однаковою підписом" - wikipedia
Це не гарне пояснення для віртуальних функцій. Тому що, навіть якщо член не є віртуальним, класи успадкування можуть його перекрити. Ви можете спробувати і самі це побачити.
Різниця проявляється, коли функція приймає базовий клас як параметр. Коли ви вводите клас успадкування як вхідний, ця функція використовує реалізацію переопределеної функції базового класу. Однак якщо ця функція віртуальна, вона використовує функцію, що реалізована у похідному класі.
Віртуальні функції повинні мати визначення в базовому класі, а також у похідному класі, але це не обов'язково, наприклад функція ToString () або toString () є віртуальним, щоб ви могли забезпечити власну реалізацію, замінивши її у визначених користувачем класах.
Віртуальні функції оголошуються та визначаються у звичайному класі.
Чиста віртуальна функція повинна бути оголошена закінченням "= 0", і вона може бути оголошена лише в абстрактному класі.
Абстрактний клас, що має чисті віртуальні функції, не може мати визначення цих чистих віртуальних функцій, тому це означає, що реалізація повинна забезпечуватися в класах, що походять від цього абстрактного класу.