C++ vs Rust — simple polymorphism comparison
This is my first Medium.com story. After reading, tweeting, and bookmarking hundreds of stories, I’ve decided to create a simple one for those of you learning Rust after coming from C++, just like me.
In this short article, we’ll compare and contrast how C++ and Rust handle dynamic polymorphism. A quick disclaimer, I’m not a Rust guru, but rather someone who’s more familiar with C++ (by the way, you can join our San Diego C++ meetup at https://www.meetup.com/San-Diego-CPP/ )
Let’s start with the purpose of polymorphism: with dynamic, runtime polymorphism, we’re able to hold a pointer or reference to a type that is actually pointing to a more concrete, derived type. It’s the basic lesson that people learn when working with OO (Object Oriented) languages. For our example, we’ll use Animal as the base, top level type, along with more concrete types, like Cat and Dog.

Animal class type has a
- Virtual default destructor. This is needed to deallocate the correct type when dealing with heap allocation. Although this is outside of the scope of this article, feel free to ask questions in the comments section.
- Virtual method/member function talk() . It is pure virtual, not implemented. The derived, concrete class(es) type(s) must implement it in order to create an instance. Here is how:

The above is simple: we create two new classes, Dog and Cat, use public inheritance from Animal, and implement the pure virtual function declared in the Animal base class, talk(). The final keyword defines that the class will be a leaf type. You cannot subclass from Dog/Cat.
Here is how we can use the class hierarchy demonstrated in “Modern C++”.

For this to compile, you will need to #include the following headers: <iostream>, <memory> and <vector>.
In the above main function, we created a vector of pointers to the Animal class type. We use unique_ptr<> to manage the heap allocation and deallocation. This is a C++11 feature. make_unique<>() is a helper function from C++14 that allocates such concrete type instances.
Finally, we create the loop (C++11 feature — range for loop) to iterate over Animal and invoke talk() on each instance. So long as each type implements the talk() interface (override virtual function of Animal base class), the type of the concrete instance is irrelevant.
Here is the output:
I'm a dogI'm a cat
Let’s do the same with Rust.
Rust is different from C++ because it implements the interfaces of the types outside of the type’s definition.
To get the point across, let’s do another example that is similar to our previous one. First, let’s implement a trait, or a definition of an interface.

We define an Animal trait with a single function that does not return anything (void) and use &self as a parameter for the function. The &self concept in Rust is similar to that of the this pointer in C++.
Next, we can define Dog/Cat and implement this trait (or feature/interface).
In Rust, we define Dog/Cat with no interface before beginning to add features. In contrast, C++ defines both the classes and their features simultaneously. Therefore, in C++, the standalone Dog/Cat class type was already capable of talk().

The last thing to implement is main(), which iterates over the Dog/Cat instances.

Rust’s Box<> is like C++’s unique_ptr<>: we create a vector of Animals and invoke talk() in each iteration, keeping the output the same as in our C++ example.
The “dyn Animal” inside the Box<> exists simply because Rust does not know the size of the Animal Trait. There is no “size” for a trait, as traits are just interfaces. In order for the program to compile, we tell Rust that Animal trait is a dynamic type that will be instantiated (heap allocated) with a concrete type that implements this trait.
That’s it for now, hope you enjoyed reading my first article on Medium. We found that despite the two language’s contrasting syntax, there are lots of similarities when implementing polymorphism semantics.