简体   繁体   English

C +中的多态和虚拟

[英]Polymorphism and virtual in C++

I'm confused about polymorphism in C++. 我对C ++中的多态性感到困惑。 I'm studying it by myself, and I understood its main features. 我自己研究它,我理解它的主要特征。 But I don't understand why it is helpful. 但我不明白为什么它有用。 Before studying polymorphism (about oop), I studied inheritance (that is helpful, because you can use a method in the superclass and subclass writing just only once). 在研究多态性(关于oop)之前,我研究了继承(这很有用,因为你可以在超类和子类中只使用一次方法编写一次)。 Now I'm stuck with polymorphism and the virtual keyword. 现在我坚持使用多态和virtual关键字。 I don't understand why it is helpful. 我不明白为什么它有用。 See the code below (it's an exercise about C++ institute (I will get a certification)). 请参阅下面的代码(这是关于C ++研究所的练习(我将获得认证))。 Why can I declare as "virtual" only functions? 为什么我可以声明为“虚拟”功能? I add in the code the variables n1 , n2 , n3 (as public), why cant I access them? 我在代码中添加了变量n1n2n3 (作为公共),为什么我无法访问它们? I don't understand at all polymorphism, I read tons of posts about polymorphism on StackOverflow, but it's as if I understood polymorphism at 50%. 我根本不了解多态性,我在StackOverflow上阅读了大量有关多态性的帖子,但就好像我理解50%的多态性一样。 I noticed that polymorphism is less difficult to understand in python because python doesn't have data types, but I want to understand it in C++ also, and its possible uses. 我注意到python中的多态性不太难理解,因为python没有数据类型,但我想在C ++中理解它,以及它的可能用途。

#include <iostream>
using namespace std;
class Pet {
    protected:
    string Name;
    public:
    Pet(string n) { Name = n; }
    virtual void MakeSound(void) { cout << Name << " the Pet says: Shh! Shh!"  << endl; }
    int n1;
};
class Cat : public Pet {
    public:
    Cat(string n) : Pet(n) { }
    void MakeSound(void) { cout << Name << " the Cat says: Meow! Meow!" <<       endl; }
    int n2;
};
class Dog : public Pet {
    public:
    Dog(string n) : Pet(n) { }
    void MakeSound(void) { cout << Name << " the Dog says: Woof! Woof!" << endl; }
    int n3;
};
int main(void) {
    Pet* a_pet1, * a_pet2;
    Cat* a_cat;
    Dog* a_dog;

    a_pet1 = a_cat = new Cat("Kitty");
    a_pet2 = a_dog = new Dog("Doggie");

    a_pet1->MakeSound();
    a_cat->MakeSound();
    static_cast<Pet*>(a_cat)->MakeSound();
    a_pet2->MakeSound();
    a_dog->MakeSound();
    static_cast<Pet*>(a_dog)->MakeSound();
}

Perhaps an example can help. 也许一个例子可以帮助。 Consider a different main() , like this: 考虑一个不同的main() ,像这样:

int main()
{
    std::vector<std::unique_ptr<Pet>> menagerie;
    menagerie.push_back(std::make_unique<Dog>("Fido"));
    menagerie.push_back(std::make_unique<Cat>("Morris"));
    menagerie.push_back(std::make_unique<Cat>("Garfield"));
    menagerie.push_back(std::make_unique<Dog>("Rover"));

    for (auto&& pet : menagerie)
    {
        pet->MakeSound();
    }
}

Here we have a bunch of pets. 在这里,我们有一堆宠物。 We can handle them all the same way, but they make different sounds. 我们可以用同样的方式处理它们,但它们会发出不同的声音。 Calling MakeSound on each does the right thing for that particular kind of pet. 在每个上面调用MakeSound对于那种特殊的宠物都是正确的。 This sort of use case is very common. 这种用例很常见。

Fido the Dog says: Woof! Woof!
Morris the Cat says: Meow! Meow!
Garfield the Cat says: Meow! Meow!
Rover the Dog says: Woof! Woof!

Now, try removing the virtual keyword and they'll all say "Shh! Shh!". 现在,尝试删除virtual关键字,他们都会说“嘘!嘘!”。

You are right, it's not easy to understand how polymorphism is useful and what it does when learning it. 你是对的,要理解多态性如何有用以及它在学习它时的作用并不容易。 The common examples like you referred doesn't really help which merely demonstrates the concept but lacks real context. 像你所提到的常见例子并没有真正帮助,它只是展示了这个概念,但缺乏真实的背景。

The understanding and be able to use polymorphism is rather advance topic in programming. 理解并能够使用多态性是编程中相当先进的主题。 It is employed when following truly object oriented programming like SOLID and design patterns. 它遵循真正的面向对象编程,如SOLID和设计模式。

A good real world example of poloymophism in action is iterator design pattern. poloymophism在行动中的一个很好的现实世界的例子是迭代器设计模式。 You define a base class say of a list with method like next() , then you can have different derived classes (for different kind of lists) all overriding this method and they implement it so you are able to iterate that list accordingly. 您可以使用next()等方法定义一个列表的基类,然后您可以使用不同的派生类(对于不同类型的列表)全部覆盖此方法并实现它,以便您可以相应地迭代该列表。

As you might be seeing it gets complicated so I can't explain everything here but you get an idea and some pointers. 你可能会看到它变得复杂,所以我无法在这里解释一切,但你得到了一个想法和一些指示。

The key idea of polymorphism is to have one method. 多态的关键思想是有一种方法。 This method will have different implementations , and a particular implementation is called based on certain situations. 该方法将具有不同的实现 ,并且基于某些情况调用特定实现。

Let's consider this example: 让我们考虑这个例子:

#include <iostream>
using namespace std;
class Polygon{

 protected:
  int numVertices;
  float *xCoord, *yCoord;

 public:
  void set(){
   cout<<"From Polygon"<< endl;
  }

};
class Rectangle : public Polygon{
public:

 void set(){
   cout<<"From Rectangle"<< endl;
}

class Triangle : public Polygon{
public:

 void set(){
   cout<<"From Triangle"<< endl;

 }
};
int main(){

 Polygon *poly;
 Rectangle rec;
 Triangle tri;

 poly = &rec;
 poly->set();
 poly = &tri;
 poly->set();
}

When you run this code your output is the following: 运行此代码时,输​​出如下:

From Polygon
From Polygon

Let's add virtual to set() in base class ( Polygon ) . 让我们在基类( Polygon )中添加virtualset() )。 Here is what you get: 这是你得到的:

From Rectangle
From Triangle

If we have created a virtual function in the base class ( Polygon ) and it is being overridden in the derived class (In this case, Triangle and Rectangle ) then we don't need virtual keyword in the derived class, functions are automatically considered as virtual functions in the derived class. 如果我们在基类( Polygon )中创建了一个虚函数并且它在派生类中重写(在本例中为TriangleRectangle ),那么我们在派生类中不需要虚拟关键字,函数会自动被视为派生类中的虚函数。

The idea is set() will call the base class version of the method if set() is not virtual even if poly is pointed to Rect. 如果set() 不是虚拟的,即使poly指向Rect, set()也会调用方法的基类版本。 On the other hand, set() that is virtual , it will call the actual method from the derived class. 另一方面, set() 是虚拟的 ,它将从派生类调用实际方法。 (In this case, rect->set() will print "From Rectangle"). (在这种情况下, rect->set()将打印“From Rectangle”)。

Doing this means that in situations where I don't know the particular type of an object, I can use virtual and polymorphism and it will use the correct method during a call. 这样做意味着在我不知道对象的特定类型的情况下,我可以使用virtualpolymorphism并且它将在调用期间使用正确的方法。

I hope this helps! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM