C++14继承类工厂实现遇E0269错误:求正确实现方式
C++14继承类工厂实现问题解答
问题描述
尝试实现一个动物类工厂,通过GetAnimal函数传入动物名称返回对应子类实例,但编译时出现错误:
E0269 conversion to inaccessible base class "Animal" is not allowed
原代码如下:
#include <iostream> class Animal { public: virtual std::string Sound(); }; class Dog : Animal { public: std::string Sound() {return "Woff!";}; }; class Cat : Animal { public: std::string Sound() {return "Meow!";}; }; class Snake : Animal { public: std::string Sound() {return "Ssss!";}; }; Animal GetAnimal(std::string name) { if (name == "Dog") return Dog(); else if (name == "Cat") return Cat(); else if (name == "Snake") return Snake(); return Animal(); } int main() { std::cout << "Sound of a dog: \"" << GetAnimal("Dog").Sound() << "\"\n"; std::cout << "Sound of a cat: \"" << GetAnimal("Cat").Sound() << "\"\n"; std::cout << "Sound of a snake: \"" << GetAnimal("Snake").Sound() << "\"\n"; return 0; }
错误原因分析
1. 私有继承导致的访问权限问题
C++中使用class定义子类时,默认继承方式是private继承,这意味着基类Animal在子类中是私有成员,外部代码无法将子类对象隐式转换为基类对象,因此return Dog();这类语句会触发"无法转换到不可访问基类"的错误。
2. 对象切片问题(即使解决权限问题后仍会出现)
如果将继承改为public,GetAnimal返回Animal对象时会发生对象切片:子类对象被截断为基类对象,子类特有的信息丢失,多态机制失效——调用Sound()时只会执行基类的版本,无法触发子类的重写逻辑。
正确实现方式
步骤1:修改为public继承
将所有子类的继承方式改为public,确保基类接口对外可见:
class Dog : public Animal { ... }; class Cat : public Animal { ... }; class Snake : public Animal { ... };
步骤2:使用指针/智能指针实现多态
工厂函数需要返回基类的指针或智能指针,避免对象切片,同时保证多态生效。推荐使用std::unique_ptr来自动管理内存,避免内存泄漏:
修正后的完整代码:
#include <iostream> #include <memory> #include <string> class Animal { public: // 纯虚函数,确保基类是抽象类,不能实例化 virtual std::string Sound() const = 0; // 虚析构函数,确保子类对象能正确被销毁 virtual ~Animal() = default; }; class Dog : public Animal { public: std::string Sound() const override { return "Woff!"; } }; class Cat : public Animal { public: std::string Sound() const override { return "Meow!"; } }; class Snake : public Animal { public: std::string Sound() const override { return "Ssss!"; } }; std::unique_ptr<Animal> GetAnimal(const std::string& name) { if (name == "Dog") return std::make_unique<Dog>(); else if (name == "Cat") return std::make_unique<Cat>(); else if (name == "Snake") return std::make_unique<Snake>(); // 返回空指针表示无效输入 return nullptr; } int main() { auto dog = GetAnimal("Dog"); if (dog) std::cout << "Sound of a dog: \"" << dog->Sound() << "\"\n"; auto cat = GetAnimal("Cat"); if (cat) std::cout << "Sound of a cat: \"" << cat->Sound() << "\"\n"; auto snake = GetAnimal("Snake"); if (snake) std::cout << "Sound of a snake: \"" << snake->Sound() << "\"\n"; return 0; }
额外优化点
- 将
Sound()声明为const成员函数(因为该函数不修改对象状态),并使用override关键字明确标注重写,提升代码可读性和安全性。 - 将
Animal的Sound()设为纯虚函数,使Animal成为抽象类,避免意外实例化基类对象。 - 添加虚析构函数,确保通过基类指针销毁子类对象时能正确调用子类的析构函数。
- 使用
const std::string&作为函数参数,避免不必要的字符串拷贝。
内容的提问来源于stack exchange,提问作者Runsva
相关产品推荐
相关产品推荐

