2015-04-06 3 views
2

Say не было никакой функции Здравствуйте, и мы просто называемся ob.display в основном, то она вызывает функцию отображения класса B, а не класс А.Ранние и позднее связывание + полиморфизм в C++

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

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

Теперь в этой программе, передавая объект как вызов по значению, вызов по указателю и вызов по ссылке на функцию Hello отлично работают. Теперь, если мы используем Полиморфизм и хотим отобразить функцию-член производного класса, если он вызывается, мы должны добавить ключевое слово virtual перед функцией отображения в базе. Если передать значение объекта при вызове с помощью указателя и вызова по ссылке это вызов функции в производном классе, но если передать объект по значению он не почему это так?>

class A 
{ 
    public: 
     void display();      // virtual void display() 
     { 
     cout << "Hey from A" <<endl; 
     } 
}; 

class B : public A 
{ 
    public: 
     void display() 
     { 
      cout << "Hey from B" <<endl; 
     } 
}; 

void Hello(A ob) // &ob //*ob 
{ 
    ob.display();  // ob->display() 
} 

int main() 
{ 
    B obj; 
    Hello(obj); // obj //&ob 
    return 0; 
} 
+0

Возможный дубликат [Что такое срез объектов?] (Http://stackoverflow.com/questions/274626/what-is-object-slicing) – Wintermute

ответ

4

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

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

B b; 
A & a = b; 

вы получите разные результаты от вызова невиртуальный функции:

b.display(); // called as B 
a.display(); // called as A 

Если вы знаете, вещественный тип, то вы можете указать, что вы хотите назвать эту версию:

static_cast<B&>(a).display(); // called as B 

но что бы ужасно неправильно, если объект a относится к не имеет типа B.

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

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

Если мы передаем значение объекта по вызову указателем и вызываем по ссылке, он вызывает функцию в производном классе, но если мы передаем объект по значению, это не значит, почему это так?

Если передать его по значению, то вы нарезки его: копирование только A части объекта, чтобы сделать новый объект типа A. Итак, независимо от того, является ли эта функция виртуальной, вызов ее на этом объекте будет выбирать версию A, так как это A и ничего, кроме A.

Если вы передаете ссылку или указатель, то вы по-прежнему обращаетесь к исходному объекту с его динамическим типом B. Таким образом, вызов виртуальной функции разрешит версию B.

+0

wikipedia говорит, что нарезка объектов происходит потому, что нет места для хранения дополнительных членов производного класса в суперклассе, поэтому он срезан. Почему нарезка объектов не происходит, если мы передаем ее ссылкой или указателем? Почему суперкласс получает дополнительное пространство для его хранения? – Stack

+1

@Stack: Если вы передаете ссылку или указатель, вы не создаете новый объект. Он относится к существующему объекту производного типа, который уже имеет достаточно места для хранения. –

0

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

Вы можете предоставить шаблонный базовый класс, как этот

template<typename Derived> 
class A { 
    public: 
     void display() { 
     // call Derived first 
     static_cast<Derived*>(this)->display(); 
     cout << "Hey from A" <<endl; 
     } 
}; 

class B : public A<B> { 
public: 
    void display() { 
     cout << "Hey from B" <<endl; 
    } 
}; 

Это хорошо известный узор, называемый CRTP и статический полиморфизм.

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