【问题标题】:The "Named Constructor Idiom" seems to contradict the rule that a static method cannot access a non-static member function. Any explanation?“命名构造函数习语”似乎与静态方法不能访问非静态成员函数的规则相矛盾。有什么解释吗?
【发布时间】:2012-01-06 14:32:05
【问题描述】:

根据site这个静态方法

static Point rectangular(float x, float y);    
static Point polar(float radius, float angle);

调用私有构造函数Point(一种非静态方法),如下所示:

#include <cmath>               // To get std::sin() and std::cos()

class Point {
 public:
   static Point rectangular(float x, float y);      // Rectangular coord's
   static Point polar(float radius, float angle);   // Polar coordinates
   // These static methods are the so-called "named constructors"
   ...
 private:
   Point(float x, float y);     // Rectangular coordinates
   float x_, y_;
 };

 inline Point::Point(float x, float y)
   : x_(x), y_(y) { }

 inline Point Point::rectangular(float x, float y)
 { return Point(x, y); }

 inline Point Point::polar(float radius, float angle)
 { return Point(radius*std::cos(angle), radius*std::sin(angle)); }
};

编辑:我很难接受答案,因为我不知道哪个是正确的。

【问题讨论】:

  • 构造函数更类似于静态成员函数而不是非静态成员函数。
  • 一个静态成员函数可以调用一个非静态成员函数,如果它有一个对象可以调用它。

标签: c++ constructor static-methods


【解决方案1】:

您不能调用构造函数,rectangular 函数也不能。它所做的只是构造一个新对象并返回它的副本。

构造函数是特殊的成员函数,没有名称,用户不能调用。它们只能作为语言的一部分被隐式调用,即通过静态或自动对象的初始化,或通过new 表达式。不能取构造函数的地址,构造函数不能是const- 或者其他限定的。

如果你这么想,那么没有人会调用任何对象的任何非静态成员函数,这没有问题的。还要注意,“成员函数”的概念对于构造函数来说是没有意义的,因为成员函数是在 objects 上调用的,但是在某个构造函数已经 之前没有任何对象完成

简而言之,构造函数是语言本身的一个特殊部分,不能仅仅视为其他概念的特例。

【讨论】:

  • “在某些构造函数完成之前没有任何对象”——好吧,标准中的术语在这一点上可能有点令人困惑。它指的是“正在建设的对象”,所以我认为有一个对象,但它的“生命周期”还没有开始。很可能这没有意义,但即使标准不是这样说的,所以它是真的。与您所说的最相关的是,可以在正在构造的对象上调用成员函数,但当然不能(直接)从包含初始化的代码中调用,它没有引用正在构造的对象。
【解决方案2】:

构造函数是一种特殊情况,因为构造函数不需要调用现有对象

您提到的规则最好记住为“静态成员函数没有隐式this指针”

【讨论】:

  • 正确,@user1042389。不过,它不需要调用一个。这就是关键。
  • 虽然我不同意你的说法“它不需要调用一个”,但我倾向于认为你得到了正确的答案,因为 构造函数不需要要调用的现有对象,因此可以从静态函数“调用”构造函数。但据我了解,示例中存在 ctor 的 this 指针,并且是在静态函数内部的堆栈上创建的临时地址。
  • @user1042389:我认为我们在同一页上。创建Point 意味着分配堆内存或保留堆栈内存,然后使用指向该内存的this 调用构造函数。在此过程中的某个时刻,会有一个有效的this 指针。
【解决方案3】:

构造函数介于静态和非静态之间:不能在对象的实例上调用构造函数,但在构造函数内部可以访问刚刚创建的对象。但是,构造函数总是被静态调用(即在类型上而不是在实例上),因此这并不是规则的真正例外。

【讨论】:

    【解决方案4】:

    您引用的“规则”背后的原因(实际上并非如此)是 static 成员函数没有它所操作的隐式实例,即没有 this

    但是,static 成员函数可以调用非static 成员函数,前提是它具有可以调用该成员函数的实例。在这种情况下,它通过调用私有构造函数来创建自己的实例。

    比较(我承认这是琐碎的例子)

    class Greeter {
        std::string who;
    
      public:
        Greeter(std::string const &name) : who(name) { }
    
        static void greet(Greeter const &gr) { gr.hello(); }
    
      private:
        void hello() { std::cout << "Hello, " << who << "!\n"; }
     };
    

    这里,static 成员greet 用于调用private 方法hello。它可以这样做是因为它传递了一个显式的Greeter 实例。 (这不适用于独立函数,除非它被声明为 friend。)

    【讨论】:

      【解决方案5】:

      rectangular() 和 polar() 通过直接调用构造函数返回未命名的 Point 对象。您通常不能从静态方法调用实例方法的原因是因为还没有实例存在。当直接调用构造函数时,它会在执行构造函数体之前创建一个未命名的实例。

      【讨论】:

        【解决方案6】:

        “命名构造成语”似乎与以下规则相矛盾: 静态方法不能访问非静态成员函数。任何 解释?

        您引用“静态成员函数不能访问非静态成员函数”的规则背后的原因是因为静态成员函数没有 this 指针。并且需要一个this函数对所有普通的非静态成员函数。

        但是构造函数是一个特殊的成员函数,有很多特殊的规则可以使用:

        例如来自 c++ 标准 3290 12.1 构造函数不能是虚拟的 (10.3) 或静态的 (9.4)。

        而且您必须已经知道,您可以在没有此类实例的情况下调用构造函数,而无需 this 指针。 这就是为什么你可以在静态成员函数中实例化一个类,或者在全局范围内实例化你喜欢的任何东西(只要它有定义):

        Point(x, y);
        

        那么这是否解释了你的问题?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-03
          • 1970-01-01
          • 2011-12-29
          • 1970-01-01
          • 2011-01-18
          • 2011-09-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多