Structs are almost exactly like the C-objects of the same name: they define layout in memory for a data structure with discrete types as fields, and there are various packing options available. However in addition to this a struct-specific implementation can exist which defines static and instance based methods. As there is no inheritance in Rust, a struct's "impl" is unique to itself.
Polymorphism is implemented via the traits system. A trait defines a set of methods that objects meant to have said trait must implement (unless a default implementation for a given method in the trait exists). Any struct can have an implementation for a given trait, so these can be considered a (rough) analog to abstract base classes/interfaces (e.g. C++ classes that are either pure virtual or have virtual functions with default implementations).
In practice, one defines an interface in C++ by having a (hopefully) stateless class with pure virtual method declarations, and then classes derived from this class must implement these methods (in order to instantiate them anyway). In Rust one defines a data structure (either a struct or enum) and then, separately, writes the "impl" for it for a trait.
But, given the case where you want dynamic dispatch, then in a sense, they are, yes.
It really just depends on what exactly you're trying to do.
What you describe for C++ is typically the case (and I've written completely unsafe, non-portable code that exploits this fact before), but I'm unsure whether that's required by the standard.