Виртуальный/чистый виртуальный пояс С++

Что именно означает, что функция определена как виртуальная и является той же, что и виртуальная?

Ответ 1

От Виртуальная функция Википедии ...

Виртуальная функция или виртуальный метод - это функция или метод, поведение которых можно переопределить внутри наследующего класса функцией с той же сигнатурой

тогда..

Чистая виртуальная функция или чистый виртуальный метод - это виртуальная функция, которая должна быть реализована производным классом, который не является абстрактным "- Wikipedia

Таким образом, виртуальная функция может быть переопределена, и должен быть реализован чистый виртуальный объект.

Ответ 2

Я хочу прокомментировать определение виртуальной Википедии, как это повторяется несколькими здесь. [В тот момент, когда этот ответ был написан,] Википедия определила виртуальный метод как тот, который может быть переопределен в подклассах. [К счастью, 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 вызывает реализацию базового класса. Это разрешено во время компиляции: компилятор видит, что bDerived является базой *, что NonVirtual не является виртуальным, поэтому он выполняет разрешение в классе Base.

Однако вызов Virtual вызывает реализацию класса Derived. Из-за ключевого слова virtual выбор метода происходит во время выполнения, а не во время компиляции. Что происходит здесь во время компиляции, так это то, что компилятор видит, что это Base *, и что он вызывает виртуальный метод, поэтому он вставляет вызов в vtable вместо класса Base. Эта виртуальная таблица создается во время выполнения, следовательно, разрешение во время выполнения для наиболее производного переопределения.

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

Ответ 3

Виртуальное ключевое слово дает С++ свою способность поддерживать полиморфизм. Когда у вас есть указатель на объект некоторого класса, например:

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, так как он является базовым классом.

Если мы сделаем это:

Duck d;
SomeFunction(&d);

он выведет '2'. Если мы это сделаем:

Horse h;
SomeFunction(&h);

он выводит "4". Мы не можем этого сделать:

Animal a;
SomeFunction(&a);

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

Чистые виртуальные функции в основном используются для определения:

a) абстрактные классы

Это базовые классы, из которых вы должны извлечь их, а затем реализовать чистые виртуальные функции.

b) интерфейсы

Это "пустые" классы, где все функции являются чисто виртуальными и, следовательно, вы должны получить и затем реализовать все функции.

Ответ 4

В классе С++ виртуальное - это ключевое слово, которое обозначает, что метод может быть переопределен (т.е. реализован) подклассом. Например:

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");
    }
}

Термин pure virtual относится к виртуальным функциям, которые должны быть реализованы подклассом и не были реализованы базовым классом. Вы определяете метод как чистый виртуальный, используя ключевое слово virtual и добавляя a = 0 в конце объявления метода.

Итак, если вы хотите сделать Shape:: initShape чистым виртуальным, вы сделаете следующее:

class Shape 
{
 ...
    virtual void initShape() = 0; // pure virtual method
 ... 
};

Добавив в ваш класс чистый виртуальный метод, вы сделаете класс абстрактным базовым классом что очень удобно для ветки интерфейсов от реализации.

Ответ 5

"Виртуальный" означает, что метод может быть переопределен в подклассах, но имеет прямо вызываемую реализацию в базовом классе. "Чистый виртуальный" означает, что это виртуальный метод без реализации с прямым вызовом. Такой метод должен быть переопределен хотя бы один раз в иерархии наследования - если класс имеет любые нереализованные виртуальные методы, объекты этого класса не могут быть построены, а компиляция завершится неудачно.

@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()

Ответ 6

Как работает виртуальное ключевое слово?

Предположим, что Человек является базовым классом, индийский - от человека.

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 do work is only called.

Если виртуальный не используется, то он статически определяется или статически привязан компилятором в зависимости от того, какой объект вызывает. Поэтому, если объект Человека называет do_work(), Man do_work() называется ДАЖЕ, ЧТО ЭТО ОТНОСИТСЯ К ИНДИЙСКОМУ ОБЪЕКТУ

Я считаю, что главный проголосовавший ответ вводит в заблуждение. Любой метод, независимо от того, имеет ли виртуальная переменная переопределенную реализацию в производном классе. С особой ссылкой на С++ правильная разница - это время выполнения (когда используется виртуальное) привязка и время компиляции (когда виртуальный не используется, но метод переопределяется, а указатель базы указывается на производный объект) связывание связанных функций.

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

"Джастин," чистый виртуальный "- это просто термин (не ключевое слово, см. мой ответ ниже), используемый для обозначения" эта функция не может быть реализована базой класс ".

ЭТО НЕПРАВИЛЬНО! Чисто виртуальные функции также могут иметь тело и могут быть реализованы! Истина заключается в том, что чистую виртуальную функцию абстрактного класса можно назвать статически! Два очень хороших автора - Бьярне Страуструп и Стэн Липпман... потому что они написали язык.

Ответ 7

Simula, С++ и С#, которые по умолчанию используют привязку статического метода, программист может указать, что определенные методы должны использовать динамическое связывание, помечая их как виртуальные. Связывание динамического метода является центральным для объектно-ориентированного программирования.

Объектно-ориентированное программирование требует трех основных понятий: инкапсуляция, наследование и привязка к динамическим методам.

Инкапсуляция позволяет детали реализации абстракция должна быть скрыта за простой интерфейс.

Наследование позволяет определить новую абстракцию как расширение или уточнение некоторых существующая абстракция, получение некоторых или всех его характеристик автоматически.

привязка динамического метода позволяет новой абстракции отображать ее новую поведение даже при использовании в контексте который ожидает старую абстракцию.

Ответ 8

Виртуальные методы МОГУТ быть переопределены путем получения классов, но им нужна реализация в базовом классе (тот, который будет переопределен)

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

Virtual соответствует поведению java по умолчанию, когда производный класс переопределяет метод базового класса.

Чистые виртуальные методы соответствуют поведению абстрактных методов в абстрактных классах. И класс, который содержит только чистые виртуальные методы и константы, будет cpp-подвеской для интерфейса.

Ответ 9

  • Виртуальные функции должны иметь определение в базовом классе, а также в производном классе, но не обязательно, например ToString() или toString() функция является виртуальной, поэтому вы можете предоставить свою собственную реализацию, переопределив ее в пользовательском режиме, (es).

  • Виртуальные функции объявляются и определяются в обычном классе.

  • Чистая виртуальная функция должна быть объявлена ​​с "= 0", и ее можно объявить только в абстрактном классе.

  • Абстрактный класс, имеющий чистую виртуальную функцию (ы), не может иметь определения (я) этих чистых виртуальных функций, поэтому подразумевается, что реализация должна предоставляться в классе (es), полученном из этого абстрактного класса.

Ответ 10

Чистая виртуальная функция

попробуйте этот код

#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 помечена как виртуальная в базовом классе. Скажем, компилятор, пытающийся выполнить поиск функции в производном классе и реализовать функцию. Если не найден, то выполните базовый. Спасибо

Ответ 11

"Виртуальная функция или виртуальный метод - это функция или метод, поведение которых может быть переопределено внутри наследуемого класса функцией с той же сигнатурой" - wikipedia

Это не является хорошим объяснением для виртуальных функций. Потому что, даже если член не является виртуальным, наследующие классы могут его переопределить. Вы можете попробовать и посмотреть сами.

Разница проявляется, когда функция принимает базовый класс в качестве параметра. Когда вы вводите наследующий класс в качестве входа, эта функция использует реализацию базового класса функции overriden. Однако, если эта функция является виртуальной, она использует ту, которая реализована в классе вывода.

Ответ 12

Виртуальная функция - это функция-член, объявленная в базовом классе и переопределенная производным классом.. Виртуальная функция является иерархической в ​​порядке наследования. Когда производный класс не переопределяет виртуальную функцию, используется функция, определенная в базовом классе.

Чистая виртуальная функция - это та, которая не содержит определения относительно базового класса. Он не имеет реализации в базовом классе. Любой производный класс должен переопределить эту функцию.