2012-06-20 2 views
0

Я читал так много блогов, и я понимаю, как использовать виртуальную функцию в C++. Но, тем не менее, я не понимаю, почему мы используем виртуальные функции. Можете ли вы дать мне пример реального мира, чтобы я мог более легко визуализировать фактическое значение виртуальной функции.концепция виртуальных функций в C++?

+0

у вас есть другой фон oop? –

+0

да, я знаю основные понятия Java. – devsda

+0

Они фактически приводят пример на Wiki http://en.wikipedia.org/wiki/Virtual_function – trumpetlicks

ответ

1

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

Делегирование будет, если у нас есть класс, называемый BroadbandConnection с помощью метода, называемого connection(). Затем ваш менеджер говорит, что мы хотим добавить шифрование, поэтому вы создаете класс BroadbandConnectionWithEncryption. Естественным инстинктом может быть использование наследования, а затем создание нового класса BroadbandConnectionWithEncryption происходит из BroadbandConnection.

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

class BroadBandConnection 
{ 
public: 
    void Connection (string password) 
    { 
     //connection code. 
    } 
}; 

class BroadBandConnectionWithEndcryption 
{ 
public: 
    void Connection (string password) 
    { 
     mbroadbandconnection.Connection(password); 
     //now do some stuff to zero the memory or 
     //do some encryption stuff 
    } 

private: 
    BroadBandConnection mbroadbandconnection; 
}; 

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

class IShape 
{ 
    virtual void Draw() = 0; 
}; 

class Square 
{ 
    void Draw() 
    { 
     //draw square on screen 
    } 
}; 

class Circle 
{ 
    void Draw() 
    { 
     //draw circle on screen 
    } 
}; 

Я сделал Draw() чисто виртуальным с = 0. Я мог бы оставить это и добавить некоторую реализацию по умолчанию. Чистый виртуальный имеет смысл для интерфейсов, где нет разумной реализации по умолчанию.

Что я могу сделать, это передать объект Shape различным методам, и им не нужно беспокоиться о том, что я только что дал им. Все, что они знают, это то, что я должен предоставить что-то, что поддерживает способность фигуры рисовать себя.

IShape* circle = new Circle(); 
IShape* square = new Square(); 

void SomeMethod (IShape* someShape) 
{ 
    someShape->Draw(); //This will call the correct functionality of draw 
} 

В будущем, как люди начинают думать о новых формах, они могут извлечь из IShape и так долго, как они реализуют некоторую функциональность для Draw. Они могут передать этот объект SomeMethod.

0

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

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

Исправьте меня, если я ошибаюсь, вот как я это понял.

1

Во-первых, this.

Теперь, пример реальной жизни. У меня есть программа с графическим интерфейсом с тремя вкладками. Каждая вкладка является объектом класса, который происходит из общей базы TabBase. Он имеет виртуальную функцию OnActivate(). Когда вкладка активирована, диспетчер вызывает ее на текущей вкладке. Есть некоторые общие действия, и есть действия, характерные для этой вкладки. Это реализовано с помощью виртуальных функций.

Выгода заключается в том, что диспетчеру не нужно знать, какой вкладкой он является. Он хранит массив указателей TabBase и просто вызывает OnActivate(). Магия виртуальных функций гарантирует правильное переопределение.

class TabBase 
{ 
    virtual void OnActivate() 
    { 
    //Do something... 
    } 
}; 

class SearchTab: public TabBase 
{ 
    void OnActivate() //An override 
    { 
     TabBase::OnActivate(); //Still need the basic setup 
     //And then set up the things that are specific to the search tab 
    } 
} 
+0

Зачем вам использовать наследование? Почему класс Tab не будет иметь событие «Активировать» *, а конкретный экземпляр «searchTab» будет иметь обработчик связанного события. Похоже, что пример на животных лучше демонстрирует виртуальные методы, тогда как представление о разных вкладках является хорошим примером делегирования. –

+0

В C++ нет встроенного представления о событиях. Роллинг ваш возможен, но довольно неуклюжий. –

0

Они действительно дают пример на Wiki

http://en.wikipedia.org/wiki/Virtual_function

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

0

Если вы знакомы с Java - это должно быть легко. В Java методы класса ALL являются фактически виртуальными. Если вы переопределите его в производном классе, и вы вызовете его с помощью ссылки на базовый класс, вызывается переопределение, а не база.

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

Java - это дроссель, полный виртуальных функций. У него просто нет явного ключевого слова для них.

0

Целью виртуальных функций является достижение dynamic dispatch.

Вы говорите, что знакомы с Java, поэтому для реального использования виртуальных функций подумайте о любом месте на Java, где вы бы использовали interface или использовали @Override по общедоступному/защищенному методу.

0

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

class animal 
{ 
    public: 
void sound() 
{ 
    cout << "nothing"; 
} 
}; 
class bird : public animal 
{ 
public: 
void sound() 
{ 
cout << "tweet"; 
} 

};

В этом случае я бы хотел переопределить bird(). Но что, если я этого не сделал? Это то, что случилось бы:

animal * a = new bird; 
a->sound(); 
**Output** 
nothing 

экран ничего не скажет, потому что для всех намерений и целей, C++ видит только животное. Однако, если вы объявили его виртуальным, он знает, как искать самый низкий метод в иерархии класса. Попробуйте еще раз:

class animal{ 
    public: 
    virtual void sound(){cout<<"nothing";} 
    }; 
class bird : public animal 
{ 
    public: 
    void sound() 
    { 
     cout << "tweet"; 
    } 
    }; 
    animal * a = new bird; 
    a->sound(); 
**Output** 
    tweet. 

Надеюсь, что это поможет.

+0

Использование однобуквенных имен для классов, которые пропускают букву, вызываемую методом переопределения, сбивает с толку. C является A с другим B? почему не простой B является A с overriden doSomething() методом? –

+0

@Doug Я отредактировал его. Теперь я считаю, вам было бы ясно. Спасибо – vijay

+0

Отлично! Я отредактирую свой нижний план. –

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