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)”。在最简单的情况下,可以通过屏幕上的下拉列表或数据库列中的代码/字符串来显示

    你不能创造“新人”——这是虚拟的

    因此,在开始将字段或数据库列加载到新对象中之前,可以通过调用工厂并向其传递一个“代码”(或其他“赠品”给一致的对象)来创建新对象,在最基本的情况下,将对其进行检查