Я читал о виртуальных функциях и нашел,
VF используются при полиморфизме наследственного класса.
Таким образом, если класс и производный класс имеют одинаковое имя функции, VF связывает соответствующую функцию с вызовом функции.
т.е. если рассматриваемая функция обозначена как виртуальная в базовом классе, то будет вызвана функция производного класса. Если он не является виртуальным, будет вызвана функция базового класса.
В Java по умолчанию: все функции виртуальные C ++: не виртуальные, и их можно сделать виртуальными в Java с помощью окончательного модификатора частного доступа, а в C ++ с помощью ключевого слова Virtual сделать функцию виртуальной.
Основываясь на приведенной выше теории, я написал код:
#include <iostream>
class base{
public :
virtual void function1(){
std::cout<<"BaseVirtual"<<std::endl;
}
void function2(){
std::cout<<"Base NonVirtual"<<std::endl;
}
};class derieved: public base
{
public :
void function1(){
std::cout<<"Derieved Virtual"<<std::endl;
}
void function2(){
std::cout<<"Derieved NonVirtual"<<std::endl;
}
};int main()
{
base b1;
derieved d1;
b1.function1();
b1.function2();
d1.function1();
d1.function2();
}
Теперь, исходя из того факта, что если это виртуальная функция, то вызывается только функция производного класса, мой вывод для вышеуказанной программы должен быть:
BaseVirtual
Base NonVirtual
Derieved Virtual
Base NonVirtual
однако, оказалось, что это:
BaseVirtual
Base NonVirtual
Derieved Virtual
Derieved NonVirtual
что должно быть правильно, конечно. Так что мой вопрос — вывод полностью нарушает утверждение Если рассматриваемая функция обозначена как виртуальная в базовом классе, то будет вызвана функция производного класса. Если он не является виртуальным, будет вызвана функция базового класса. для звонка:
d1.function2();
Да … роль виртуального становится очевидной тогда и только тогда, когда вы пытаетесь получить доступ к производному объекту класса с помощью указателя базового класса.
С вами пример: —
#include <iostream>
class base{
public :
virtual void function1(){
std::cout<<"BaseVirtual"<<std::endl;
}
void function2(){
std::cout<<"Base NonVirtual"<<std::endl;
}
};class derieved: public base
{
public :
void function1(){
std::cout<<"Derieved Virtual"<<std::endl;
}
void function2(){
std::cout<<"Derieved NonVirtual"<<std::endl;
}
};int main()
{
base *b1;
derieved d1;
b1=&d1;
b1->function1();
b1->function2();
return 0;
}
выход:-
Derieved Virtual
Base NonVirtual
Прямо сейчас вы создаете один объект каждый из base
а также derived
и затем вызывая function1
а также function2
непосредственно на этих объектах. В этих условиях virtual
(или его отсутствие) не имеет значения вообще.
По крайней мере, в C ++, для virtual
чтобы что-то значить, вам нужно работать с указателем (или ссылкой) на базовый класс, который ссылается на объект, который может быть либо базовым, либо производным классом:
base *b2 = &d1;
// invoke non-virtual function. Inovkes base::function1, because we're using
// pointer to base.
b2->function1();
// invoke virtual function. Invokes derived::function2 because the pointee object
// is a derived.
b2->function2();
Это особенно полезно, если у вас есть (например) коллекция указателей на объекты, где объекты, на которые ссылаются эти указатели, могут быть любого из нескольких различных типов. Одним из классических примеров является база shape
класс, с line
, circle
, square
и т. д. вытекает из него. Когда вы вызываете draw
член каждого, каждый рисует свою форму. В этом конкретном случае ваш базовый класс, вероятно, является абстрактным базовым классом — draw
член объявлен «чисто виртуальным», то есть вы не можете создать объект базы shape
класс, и для создания экземпляра производного класса, который должен переопределить draw
функция-член:
class shape {
public:
virtual void draw() = 0;
};
class circle : public shape {
public:
virtual void draw() { /* draw itself */ }
};
Затем в вашей программе для рисования у вас есть коллекция (указателей) фигур, созданных пользователем, и чтобы нарисовать их все, вы просто проходите через коллекцию и говорите каждой нарисовать себя. Код более высокого уровня не должен знать или заботиться о том, является ли конкретная форма кругом, квадратом, треугольником и т. Д.
for (int i=0; i<shapes.size(); i++)
shapes[i]->draw();
Полиморфизм в C ++ требует использования указателей. Если вы измените свой пример на:
base *b1 = new base();
base *d1 = new derived();
Это на самом деле будет использовать виртуальный механизм. Тем не менее, вы, кажется, путаете с основными идеями полиморфизма. Если вы определяете класс как производный, он будет вызывать функции, определенные в derived
класс, а также с base
,
Изменить: Чтобы сделать это более явным, вот вывод и объяснение:
b1->function1(); //Will call base::function1()
b1->function2(); //Will call base::function2()
d1->function1(); //Will call derived::function1()
d2->function2(); //Will call derived::function2()
Все полиморфизм / виртуальные вызовы позволяют вам обрабатывать производный указатель как базовый тип, вызывая (правильные) производные функции для него. Так что, если у вас была другая функция, такая как:
void foo(base& b)
{
b.function1();
}
Потом прохождение b1
позвоню base::function1()
, проходя d1
позвоню derived::function1()
,