C+中的接口类和工厂函数+; 迈尔斯有效C++项目31(第三版中的P147),他谈到接口类。他展示了一个带有纯虚方法的Person类和一个派生类RealPerson的示例。它看起来像这样,尽管我已经简化了它并添加了一些琐碎的实现 #include <string> class Person { public: virtual ~Person() {}; virtual std::string name() const = 0; }; class RealPerson : public Person { public: RealPerson(const std::string& name) : theName(name) {} virtual ~RealPerson() {}; virtual std::string name() const { return theName; } private: std::string theName; }; #包括 班主任{ 公众: 虚拟的~Person(){}; 虚拟std::string name()const=0; }; 类真实人:公众人物{ 公众: RealPerson(const std::string&name):名称(name){} 虚拟~RealPerson(){}; 虚拟std::string name()常量{返回名称;} 私人: std::字符串名称; };
他接着说,我们可以很容易地创建一个“工厂功能”来创建真实的人:C+中的接口类和工厂函数+; 迈尔斯有效C++项目31(第三版中的P147),他谈到接口类。他展示了一个带有纯虚方法的Person类和一个派生类RealPerson的示例。它看起来像这样,尽管我已经简化了它并添加了一些琐碎的实现 #include <string> class Person { public: virtual ~Person() {}; virtual std::string name() const = 0; }; class RealPerson : public Person { public: RealPerson(const std::string& name) : theName(name) {} virtual ~RealPerson() {}; virtual std::string name() const { return theName; } private: std::string theName; }; #包括 班主任{ 公众: 虚拟的~Person(){}; 虚拟std::string name()const=0; }; 类真实人:公众人物{ 公众: RealPerson(const std::string&name):名称(name){} 虚拟~RealPerson(){}; 虚拟std::string name()常量{返回名称;} 私人: std::字符串名称; };,c++,C++,他接着说,我们可以很容易地创建一个“工厂功能”来创建真实的人: std::shared_ptr<Person>Person::create(const std::string& name) // EDIT - removed tr1:: { return std::shared_ptr<Person>(new RealPerson(name)); } std::shared\u ptrPerson::create(const std::string&na
std::shared_ptr<Person>Person::create(const std::string& name) // EDIT - removed tr1::
{
return std::shared_ptr<Person>(new RealPerson(name));
}
std::shared\u ptrPerson::create(const std::string&name)//编辑-删除tr1::
{
返回std::shared_ptr(新RealPerson(name));
}
当我可以用正常的方式实例化RealPerson类时,为什么我要使用这个“create”函数呢
另外,为什么派生类方法是“虚拟的”
编辑
谢谢你的评论。我(现在)理解了它的用途,但我不知道它与任何层次结构中的任何基类有什么不同——这样的工厂函数在所有基类中都是典型的吗?它也有一种混乱的感觉,而不是语言的一部分。但是我对C++是比较新的,所以这可能是我的问题。
当我可以用正常的方式实例化RealPerson类时,为什么我要使用这个“create”函数呢
这样用户就不需要知道实现Person
界面的具体类型;他们只需要知道制造他们想要的那种人的工厂功能
另外,为什么派生类方法是虚拟的
因为它们在基类中声明为
virtual
。是否也在派生类中声明它们virtual
,这是可选的;无论您是否这样做,它们都是虚拟的。一个简单的原因是您将create函数扩展为如下内容:
std::tr1::shared_ptr<Person>Person::create(const std::string & obj,const std::string& name)
{
if(obj=="RealPerson")
return std::tr1::shared_ptr<Person>(new RealPerson(name));
else if ( obj == "ImaginaryPerson")
return std::tr1::shared_ptr<Person>(new ImaginaryPerson(name));
// Lets assume there exists some other class ImaginaryPerson: public Person ..
return std::tr1::shared_ptr<Person>();
}
std::tr1::shared_ptrPerson::create(const std::string&obj,const std::string&name)
{
如果(obj==“真实人”)
返回std::tr1::shared_ptr(新RealPerson(name));
else if(obj==“想象中的人”)
返回std::tr1::shared_ptr(新形象人(姓名));
//让我们假设还有另外一类人:公众人物。。
返回std::tr1::shared_ptr();
}
通过使用不同的对象调用create函数,可以创建不同类型的Person对象
基类被标记为虚拟,因为有人可能希望将RealPerson类扩展为RealPersonWithHair类,该类具有不同的
name()
实现。如果以真实方式实例化RealPerson
,则必须在编译时知道您想要的是RealPerson
。工厂方法返回一个共享的\u ptr
,因此代码可以在运行时决定创建什么类型的人员
;根据具体情况,该方法可能会决定为您提供一个虚构人物
、柏拉图式人物
、长死人
或其他什么
派生类方法是虚拟的,因为您可能希望从RealPerson
派生其他类,如YoungRealPerson
Person
接口的库的客户端,甚至不知道RealPerson
类的存在。或者,对于名字以“John”开头的人,该库可能有一个优化的实现,并且可能返回一个JohnPerson
,而不是基于名字的RealPerson
。作为客户,你不需要知道,也不应该关心
请注意,这不一定是一个严格的库客户机场景,也可以是一个应用程序的不同模块/部分。尽管如此,“编码到接口,而不是实现”仍然是一种很好的实践,因为它加强了封装并促进了单元测试
virtual
时,它的重写器将自动虚拟,无论您是否将关键字放在它们旁边。然而,把它放在那里作为提醒是一种很好的做法。在C++11中,还强烈建议您提供重写
说明符,以便编译器检查您是否在打算重写时实际重写
您可以在许多关于设计模式的书籍中找到有关factory函数的信息。简而言之,它是一个具有不同行为的构造函数,根据参数(RealPerson、FootballPlayer或从Person派生的任何其他类)返回不同的对象 派生类中不需要virtual关键字。它提醒您该方法是虚拟的。当您有多个子类时,它用于选择正确的子类。 并将该逻辑保持在一个地方,以使其可维护(OO+过程杜德!!) 如果您有一个数据库或数据输入屏幕,可以存储或允许输入多个人,当您想编写一个函数来读取屏幕以创建新的person对象,或者从数据库加载记录时,第一行不能是“new RealPerson(name);”。数据输入屏幕或数据库记录可能在谈论“ImaginaryFriend(name)”。在最简单的情况下,可以通过屏幕上的下拉列表或数据库列中的代码/字符串来显示 你不能创造“新人”——这是虚拟的 因此,在开始将字段或数据库列加载到新对象中之前,可以通过调用工厂并向其传递一个“代码”(或其他“赠品”给一致的对象)来创建新对象,在最基本的情况下,将对其进行检查