2015-06-30 3 views
-5
using namespace std; 

class Foo 
{ 
    public: 
     virtual void foo(); 
     void foo2(); 
}; 
class Bar : public Foo 
{ 
    public: 
     void foo(); 
     void foo2(); 
}; 
int main() 
{ 
    Foo* f = new Foo; 
    f->foo();   **//1** 
    f->foo2();  **//2** 
    return 0; 
} 

Как компилятор знает, 1) является динамическим по своей природе и 2) является статическим. Как оба вызываются внутри.Как называются виртуальные и не виртуальные функции

+0

Если я неправильно понял намерение вашего вопроса, и это больше похоже на то, как «компилятор разрешает, какую функцию вызывать для виртуальных функций», затем [читайте здесь] (https://stackoverflow.com/questions/ 3103153/overloaded-virtual-function-call-resolution) – CoryKramer

+1

Вы должны посмотреть FAQ [isocpp.org] (https://isocpp.org/) на [виртуальные функции] (https://isocpp.org/ wiki/faq/virtual-functions # overview-virtual-fns) – NathanOliver

+0

Я написал код намеренно, чтобы уточнить сомнение, в 1) компилятор решит использовать виртуальную таблицу, которую он должен вызвать Foo :: foo, поскольку указатель имеет базовый класс & in 2) компилятор решает статически вызвать Foo :: foo2. Итак, как компилятор дифференцируется в обеих ситуациях, прочитав инструкцию. –

ответ

0

В вашем примере как foo(), так и foo2() будет из класса Foo.

int main() 
{ 
    Foo* f = new Foo; 
    f->foo();      // Foo::foo 
    f->foo2();      // Foo::foo2 
    return 0; 
} 

Для вас, чтобы проиллюстрировать virtual поведения, вам нужно сделать экземпляр производного класса

int main() 
{ 
    Foo* b = new Bar; 
    b->foo();      // Bar::foo 
    b->foo2();      // Foo::foo2 
    static_cast<Bar*>(b)->foo2(); // Bar::foo2 
    return 0; 
} 

Уведомления в последнем случае, так как b фактически Bar, он вызывает переопределенную виртуальный способ foo. Но так как foo2 не объявлен virtual и b является Foo, он будет вызывать Foo::foo2. Однако, если мы бросим f к Bar, он будет вызывать Bar::foo2

2

Collected from here . . .

функции Невиртуальные члены разрешаются статически. То есть функция-член выбирается статически (во время компиляции) на основе типа указателя (или ссылки) на объект.

Напротив, виртуальные функции-члены решаются динамически (во время выполнения). То есть функция-член выбирается динамически (во время выполнения) в зависимости от типа объекта, а не от типа указателя/ссылки на этот объект. Это называется «динамическое связывание». Большинство компиляторов используют некоторый вариант следующего метода: если объект имеет одну или несколько виртуальных функций, компилятор помещает скрытый указатель в объект, называемый «виртуальный указатель» или «v-указатель». «Этот v-указатель указывает на глобальную таблицу, называемую« виртуальная таблица »или« v-таблица ».

Чистая виртуальная функция - это функция, которая должна быть переопределена в производном классе и не нуждается в определении. Виртуальная функция объявляется «чистой», используя синтаксис curious = 0. Например:

class Base { 
public: 
    void f1();  // not virtual 
    virtual void f2(); // virtual, not pure 
    virtual void f3() = 0; // pure virtual 
}; 
Base b; // error: pure virtual f3 not overridden 

Здесь Base является абстрактным классом (поскольку он имеет чисто виртуальную функцию), так что ни один объект класса Base не может быть создан непосредственно: База (явно) означает, что базовый класс. Например:

class Derived : public Base { 
    // no f1: fine 
    // no f2: fine, we inherit Base::f2 
    void f3(); 
}; 
Derived d; // ok: Derived::f3 overrides Base::f3 

Пример для виртуальных или Невиртуальных Fenction

#include <iostream> 
using namespace std; 

class Base { 
    public: 
      virtual void NameOf(); // Virtual function. 
      void InvokingClass(); // Nonvirtual function. 
      }; 

// Implement the two functions. 
void Base::NameOf() { 
    cout << "Base::NameOf\n"; 
    } 

void Base::InvokingClass() { 
    cout << "Invoked by Base\n"; 
    } 

class Derived : public Base { 
    public: 
      void NameOf(); // *Virtual function*. 
      void InvokingClass(); // *Nonvirtual function.* 
    }; 

// Implement the two functions. 
void Derived::NameOf() { 
    cout << "Derived::NameOf\n"; 
} 

void Derived::InvokingClass() { 
    cout << "Invoked by Derived\n"; 
} 

Главной

int main() { 
    // Declare an object of type Derived. 
     Derived aDerived; 

    // Declare two pointers, one of type Derived * and the other 
    // of type Base *, and initialize them to point to aDerived. 
     Derived *pDerived = &aDerived; 
     Base *pBase = &aDerived; 

    // Call the functions. 
    pBase->NameOf();   // Call virtual function. 
    pBase->InvokingClass(); // Call nonvirtual function. 
    pDerived->NameOf();  // Call virtual function. 
    pDerived->InvokingClass(); // Call nonvirtual function. 
} 
0

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

Чтобы просмотреть динамическое связывание в действии, создайте указатель Foo с объектом Bar, см. Ниже код.

#include <iostream> 
#include <string> 
#include <algorithm> 

using namespace std; 

class Foo 
{ 
    public: 
     virtual void foo(){std::cout<<"Foo foo"<<std::endl;}; 
     void foo2(){std::cout<<"Foo foo2"<<std::endl;}; 
}; 
class Bar : public Foo 
{ 
    public: 
     void foo(){std::cout<<"Bar foo"<<std::endl;}; 
     void foo2(){std::cout<<"Bar foo2"<<std::endl;}; 
}; 
int main() 
{ 
    Foo* f = new Bar; 
    f->foo(); 
    f->foo2(); 
    return 0; 
} 
+0

Я написал код намеренно, чтобы уточнить сомнение, в 1) компилятор решит использовать виртуальную таблицу, которую он должен вызвать Foo :: foo, поскольку указатель имеет базовый класс и в 2) компилятор решает статически вызвать Foo :: foo2. Итак, как компилятор дифференцируется в обеих ситуациях, прочитав инструкцию. –

0

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

class Foo { 
    void foo_impl(){std::cout<<"Foo foo"<<std::endl;} 
    struct { 
     void (*foo_ptr)(); 
    } vtable; 
    public: 
     Foo(){vtable.foo_ptr = &Foo::foo_impl;} 
     void foo(){vtable.foo_ptr();} 
     void foo2(){std::cout<<"Foo foo2"<<std::endl;} 
}; 
class Bar : public Foo { 
    void foo_impl(){std::cout<<"Bar foo"<<std::endl;} 
    public: 
     Bar(){vtable.foo_ptr = &Bar::foo_impl;} 
     void foo2(){std::cout<<"Bar foo2"<<std::endl;} 
}; 

Таким образом, при вызове виртуальной функции, адрес сначала просматривается в vtable, поэтому, если вы назначили Bar bar; Foo& foo = bar;, тогда foo.foo() звонит Bar в foo() вместо Foo.

 Смежные вопросы

  • Нет связанных вопросов^_^