一个静态方法可以访问同一类中的私有方法吗?

36
因为单例/命名构造函数,我有一个问题。在这两种情况下,真正的构造函数都是受保护或私有的,不能从外部访问。
例如,一个简短的命名构造函数如下:
 class A
{
  public:
    static A createA() { return A(0); } // named constructor
  private:
    A (int x);
};
int main(void)
{
   A a = A::createA(); 
}

我曾认为静态方法只能访问静态数据成员,或通过现有对象访问私有数据/方法。 但是,在上面的代码中,私有构造函数A()不是静态的,并且在调用它的时候也不存在对象。 因此,我唯一能想到的解释是静态方法可以访问同一类的非静态私有方法。请问是否有人可以肯定或否定我的想法,并可能附上一些解释?

如果这太琐碎了,请原谅,但关键词太常见了,我在数十页的谷歌搜索结果中都找不到答案。提前感谢。


DR;TL;是的,它可以。 - 101010
为什么你把答案放在问题部分?如果你想回答自己的问题,可以这样做,但请将其作为答案而不是问题的补充。 - 463035818_is_not_a_number
@tobi303 我发现有几次op总结了一个简短的答案。所以我认为这是我应该做的事情。如果我误解了,请告诉我,我会删除总结部分。谢谢。 - Flowing Cloud
@FlowingCloud 我认为只有在极少数情况下才适用(例如当有许多不同的答案,而对它们进行总结可以帮助读者时),但通常用户期望问题在问题中,答案在答案中。一个强有力的反对意见是赞成/反对票。如果你把答案放在问题中,就没有办法对你的总结进行赞成/反对投票了。 - 463035818_is_not_a_number
@tobi303 当然,我会删除它们。感谢您指出这个问题。 - Flowing Cloud
显示剩余3条评论
6个回答

29

一个静态成员函数与非静态成员函数有相同的访问权限。因此,它可以访问类中任何公共、受保护和私有的变量。但是,你需要向该函数传递该类的实例才能让该函数访问该成员。否则,静态函数只能直接访问类中的其他静态成员。


这就是我感到困惑的地方。在我调用构造函数的时候,对象甚至还不存在。因此,当没有任何实例存在时,静态函数能够访问私有构造函数吗? - Flowing Cloud
3
@FlowingCloud请看下方:静态函数可以访问私有成员,但除此之外,它与在类外定义的任何函数一样。要运行构造函数,您不需要对象。但对于其他非静态类方法,您需要一个对象。 - rainer
简单来说,这就是规则。我的老板喜欢说一个类始终是它自己的 friend - Fitzwilliam Bennet-Darcy
3
@FlowingCloud 构造函数就像静态函数一样。它不需要实例,因为它正在创建一个实例,这就是为什么它被称为特殊成员函数。因此,调用它是可以的,因为您不需要实例。 - NathanOliver
谢谢大家!我现在明白了! - Flowing Cloud
@FlowingCloud 没问题。很高兴能帮忙。 - NathanOliver

14
根据标准§11/p2 成员访问控制 [class.access] (强调我的)

类的成员也可以访问该类具有访问权限的所有名称。成员函数的本地类可以访问与该成员函数本身可以访问的相同名称。113

113) 因此,嵌套和本地类的访问权限是可传递和累积的。

由于静态成员函数是类的成员,因此它具有访问该类具有访问权限的所有名称的权限,因此也可以访问类本身的构造函数。

因此,在您的示例中:

class A {
  A(int x);  
public:
  static A createA() { return A(0); } // named constructor  
};

A::createA() 是一个静态成员函数,可以访问调用 A::A(int) 私有构造函数。


4

在类的函数中(包括static函数),“所有”私有成员数据和函数都是可访问的,即使您在该函数内处理不同的类“实例”。

在编写复制构造函数赋值运算符时经常利用这一点。

(我的老板经常谈论他想使用某种friend = delete;语法来禁用这种行为。)


1
我认为静态方法在没有对象的情况下无法访问私有数据成员,我是对的吗?我更想知道静态方法是否可以访问私有方法(构造函数)?//我看到了你上面的解释。谢谢! - Flowing Cloud
不,你总是需要一个对象来引用非静态数据成员。但是静态函数可以调用私有函数;在你的情况下是构造函数 - Fitzwilliam Bennet-Darcy
抱歉,只是需要澄清一下。静态函数可以调用任何私有函数吗,还是只能调用构造函数(不涉及对象引用)? - Flowing Cloud
2
一个静态函数只能调用静态函数或构造函数。 - Fitzwilliam Bennet-Darcy
明白了!谢谢! - Flowing Cloud

2

是的,它可以。静态函数可以访问私有成员,但除此之外,它就像类外定义的任何函数一样。特别是,由于它没有 this 指针(即没有“绑定”到任何特定实例),您将无法直接访问任何成员(这些成员始终“绑定”到实例):如果您想要那样做,则需要从某个地方获取一个实例:

#include <iostream>
using namespace std;

class A
{
  public:
    static A createA() { return A(0); }
    static void dosomething(A *a) { return a->something(); }
  private:
    A (int x) { cout << "ctor" << endl; }
    void something() { cout << "something" << endl; }
};

int main(void)
{
   A a = A::createA(); 
   A::dosomething(&a); 
   return 0;
}

这正是问题所在:当调用静态方法创建对象时,还不存在对象。那么它是如何能够访问私有构造函数的呢? - Flowing Cloud
我看到了你上面的进一步解释。谢谢! - Flowing Cloud

2

对此进行跟进,为什么不允许这样做?如果允许创建对象,为什么不允许创建指向它的指针?

using namespace std;
class A
{
  public:
    static std::unique_ptr<A> createA() {
    return std::make_unique<A>(0);
    }
  private:
    A (int x) { y = x;}
    int y;
};
int main(void)
{
   auto a = A::createA(); 
   return 0;
}

1
也许这应该作为一个新问题提出。那样会得到更多的关注。 - navneeth
1
这是因为你的构造函数是私有的,所以它无法从std::make_unique()库调用中实例化。如果你的构造函数是公共的就可以了。 - Zenul_Abidin
在这种情况下,返回 std::unique_ptr<A>(new int(0)); 是被允许的。我很好奇是否有人知道如何避免在这种情况下使用 "new",因为在现代 C++ 中这似乎是不受欢迎的。 - Dale Barnard

0

你的静态方法没有访问任何现有实例的静态成员或非静态成员。
它只是创建了一个新的实例。


1
是的,构造函数确实也会执行。但构造函数不是一个实例方法。构造函数私有与否无关紧要:成员(静态或非静态)可以访问在该类中定义的任何内容。 - Robert Kock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接