派生类对象存入父类类型容器后,如何访问其成员函数?
The issue you're hitting is called object slicing—this is exactly what's happening when you store a B object into a container that holds A instances. Let me break this down and show you how to fix it.
What's Object Slicing?
Your AVector is built on top of a std::vector<A>, which stores actual A objects (not references or pointers). When you pass a B object to push_back, the compiler only copies the base class (A) portion of the B object into the vector. All the unique parts of B (like the sayHello() method) get "sliced off"—the vector element is now just a plain A, with no trace of B left. That's why you can't call sayHello() or cast it back to B* later.
How to Preserve Derived Class Information
To keep the full B object intact, you need to store pointers (or smart pointers) to A (and its derivatives) instead of storing the objects directly. Pointers don't get sliced—they just point to the full object in memory. Here's how to adjust your code:
Step 1: Update the Base Class with Virtual Functions
First, add a virtual destructor to A (critical for safely deleting derived objects via base pointers) and make sayHello() a virtual function so you can call it polymorphically:
#include <iostream> #include <vector> #include <memory> // For smart pointers class A { private: int id_; public: A(int id); virtual ~A() = default; // Virtual destructor for safe cleanup int id() { return id_; } virtual std::string sayHello() const { return "From Base A"; } // Virtual method }; A::A(int id) : id_{id} {} class B : public A { public: B(int id); std::string sayHello() const override { return "Hello"; } // Override base method }; B::B(int id) : A(id) {}
Step 2: Modify AVector to Store Smart Pointers
Replace the underlying std::vector<A> with std::vector<std::unique_ptr<A>> (using unique_ptr is safer than raw pointers because it handles automatic cleanup):
class AVector : private std::vector<std::unique_ptr<A>> { public: // Push a pre-made unique_ptr<A> void push_back(std::unique_ptr<A> obj) { std::vector<std::unique_ptr<A>>::push_back(std::move(obj)); } // Helper to emplace a derived class directly (cleaner syntax) template<typename Derived> void emplace_back(int id) { std::vector<std::unique_ptr<A>>::emplace_back(std::make_unique<Derived>(id)); } // Bring over the vector methods you need using std::vector<std::unique_ptr<A>>::size; using std::vector<std::unique_ptr<A>>::at; using std::vector<std::unique_ptr<A>>::begin; using std::vector<std::unique_ptr<A>>::end; };
Step 3: Use the Container Correctly in Main
Now you can store A and B objects without slicing, and call their methods polymorphically:
int main() { AVector av; // Emplace A and B objects directly into the container av.emplace_back<A>(3); av.emplace_back<A>(8); av.emplace_back<B>(12); // Call sayHello() polymorphically via the base pointer std::cout << av.at(2)->sayHello() << std::endl; // Outputs "Hello" // If you need to cast to B* (to access B-specific methods not in A), use dynamic_cast if (B* b_ref = dynamic_cast<B*>(av.at(2).get())) { std::cout << "Casted to B successfully, id: " << b_ref->id() << std::endl; } else { std::cout << "Object at index 2 is not a B" << std::endl; } return 0; }
Key Takeaways
- Object slicing happens when you store a derived class object in a base class container—only the base part is kept.
- Store smart pointers (like
unique_ptr) to the base class to preserve the full derived object. - Use virtual functions to enable polymorphic calls (calling derived methods via base pointers).
dynamic_castlets you safely convert a base pointer back to a derived pointer (it returnsnullptrif the conversion isn't valid, so always check the result).
内容的提问来源于stack exchange,提问作者Michael Schäfer

