2010-11-09 165 views
0

我看到下面的代码:
http://sourcemaking.com/design_patterns/singleton/cpp/1静态成员变量可以调用非静态成员函数吗?

class GlobalClass 
{ 
private: 
    int m_value; 
    static GlobalClass *s_instance; 
    GlobalClass(int v = 0) 
    { 
     m_value = v; 
    } 
public: 
    int get_value() 
    { 
     return m_value; 
    } 
    void set_value(int v) 
    { 
     m_value = v; 
    } 
    static GlobalClass *instance() 
    { 
     if (!s_instance) 
      s_instance = new GlobalClass; 
     return s_instance; 
    } 
}; 

GlobalClass *GlobalClass::s_instance = 0; 

void foo(void) 
{ 
    GlobalClass::instance()->set_value(1); // static variable calls non-static functions 
    cout << "foo: global_ptr is " << GlobalClass::instance()->get_value() << '\n'; 
} 

据我所知(请纠正我,如果我错了这里),

  1. 静态函数只能访问(读/写)静态成员变量

  2. 非静态函数可以访问(写入/读取)静态成员变量

基于上面的示例,似乎静态变量可以访问非静态函数。
这是正确的吗?

回答

5

变量不叫什么

(这并没有真正解决示例代码,但它的两个“规则”的代码下面列出的纠正一个误解)

静态成员函数是一个成员,并且可以访问其类的所有公共,受保护和私有成员,包括静态和实例。

但是,静态成员函数没有this指针,因此要访问实例成员,需要指定实例。

+2

静态成员函数不能访问非静态成员变量。 – q0987 2010-11-09 04:48:54

+5

@ q0987:是的,它可以。我可以给你一个例子,但我真的希望你停下来,首先想想我的答案。学习思考软件是学习编程非常重要的一部分。 – 2010-11-09 05:05:30

+3

以下是您的示例:http://ideone.com/gX5wF – 2010-11-09 05:10:43

3

instance顾名思义就是返回一个指向实例的指针。它也使用静态实例指针字段s_instance。这是静态的这一事实意味着每个类只有一个s_instance字段。一旦获得该实例指针(来自instance),就可以像使用其他实例指针一样使用它。您通过静态方法获得的事实,并且该方法使用静态字段是无关紧要的。

静态方法本身是有效的;它不会隐式或显式使用this

+0

比我能管理的更简洁。我认为他也感到困惑,s_instance本身是静态的,而不仅仅是他得到指针的方法。 – Phil 2010-11-09 07:52:11

+0

@菲尔,好点。我添加了一些关于该领域的讨论。 – 2010-11-09 15:58:12

4

看来,一个静态变量可以访问非静态函数。

你的代码并不完全符合你刚才所说的。

为了理解它在做什么,让我们回过头来谈谈class的真正含义。类定义新类型。另一种类型是int。一个int实例可以位于函数局部变量或参数中,它可以通过调用new int存储在堆上,它可以是全局的,只需在文件范围内声明一个即可。他们都不知道或不在乎他们的存储位置,但他们都是int类型的实例。

当您创建class的实例时,您正在创建所使用的空间以及该类实例上的行为,并且这些行为同样适用于每个实例。

类也可以做一些不是定义其实例的数据和行为的一部分,而这些是类的静态成员。

由于这些概念基本上是分开的,所以它们并不真正互相干扰。实际上,您可以让该类的静态成员之一引用该类的一个实例,而这正是单例模式的例子。

所以实际上发生了什么,从一开始就是创建一个类的实例,使用new GlobalClass,然后将指针保持在某个位置。碰巧指针被保存为定义刚刚创建的实例类型的同一类的静态成员。

然后GlobalClass提供了使用该实例的机制。当你调用GlobalClass::instance()时,它会读取一个允许的静态类变量。该变量包含一个指针,该指针在解除引用时(通过->)会导致我们先前创建的一个对象,并且该对象因为它是GlobalClass的一个实例,现在允许访问实例变量。

+0

Hello TokenMacGuy,GlobalClass :: instance()返回s_instance,它是一个静态成员变量。所以我假设这个函数返回一个静态成员变量。我对么? - 谢谢 – q0987 2010-11-09 04:44:01

+0

@ q0987 - 是的,这是正确的。静态方法不能访问非静态方法,但是一个实例(静态或其他)可以访问两者。 – Phil 2010-11-09 04:49:02

+0

@菲尔,这是我感到困惑的一点。由于返回的实例是一个静态变量。这个静态变量如何调用非静态成员函数set_value并更改非静态成员变量m_value?换句话说,一个静态变量如何确定使用哪个“this”? - 谢谢 – q0987 2010-11-09 04:57:03

1

技术问题已经发布在其他答案中,我只是添加一个试图帮助解决混乱的例子。想象一下,你创建了一个Human类来表示一个人,它可以拥有诸如眼睛的颜色,名称等等的属性以及定义诸如步行,跳跃等动作的方法......这些属性和方法是特定的给人类的每个实例:一个特定的人可能有蓝眼睛,你可以让她说话。

在不同的层次上,可能会有不属于实例的特性或行为,而是涉及到整个人类,比如谁是最高或最高级的人类。那些被宣称为静态属于整个人类,而不是每个人。

现在,一旦你从班上获得一个人,说最高,那个人是一个人,因此你可以要求任何你想要的财产,或者你可以要求你需要的任何行动:Human::get_tallest().get_something_from_cupboard()将要求最高(get_tallest())集体中的人(集体诉讼),然后请求特定的个人为您执行某项操作(get_something_from_cupboard()),这是由特定的实例执行的操作。