【问题标题】:namespace and private static class members命名空间和私有静态类成员
【发布时间】:2012-05-27 06:56:33
【问题描述】:

为什么会这样:

#include "iostream"

class Something {
private:
    static int s_nIDGenerator;
    int m_nID;
    friend int main();
public:
     Something() { m_nID = s_nIDGenerator++; }
     int GetID() const { return m_nID; }
};

int Something::s_nIDGenerator;

int main() {
    Something::s_nIDGenerator = 1;

    Something cFirst;
    Something cSecond;
    Something cThird;

    using namespace std;
    cout << cFirst.GetID() << endl;
    cout << cSecond.GetID() << endl;
    cout << cThird.GetID() << endl;
    return 0;
}

打印出来:

1
2
3

这失败了:

#include "iostream"

namespace test {   
    class Something {
    private:
            static int s_nIDGenerator;
            int m_nID;
            friend int main();
    public:
            Something() { m_nID = s_nIDGenerator++; }
            int GetID() const { return m_nID; }
    };
};

int test::Something::s_nIDGenerator;

int main() {
    using namespace test;
    Something::s_nIDGenerator = 1;
    // or test::Something::s_nIDGenerator = 1;  same effect if not using using.

    Something cFirst;
    Something cSecond;
    Something cThird;

    using namespace std;
    cout << cFirst.GetID() << endl;
    cout << cSecond.GetID() << endl;
    cout << cThird.GetID() << endl;
    return 0;
}

带有编译器错误信息:

**** Internal Builder is used for build               ****
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src\tuttest1.o ..\src\tuttest1.cpp
..\src\tuttest1.cpp: In function 'int main()':
..\src\tuttest1.cpp:23:5: error: 'int test::Something::s_nIDGenerator' is private
..\src\tuttest1.cpp:27:13: error: within this context
Build error occurred, build is stopped
Time consumed: 161  ms. 

如何让第二个示例使用命名空间测试工作?

对象周围的命名空间声明如何/为什么阻止静态成员表单被访问?


根据我对@zmo 的评论,这是我根据他的线索要做的工作:

(评论没有空间或格式,我不得不编辑,因为我无法设置这个答案......(不管它需要什么。)

#include "iostream"

namespace test {
    class Something {
    private:
        static int s_nIDGenerator;
        int m_nID;
        friend void load(int);
    public:
        Something() { m_nID = s_nIDGenerator++; }
        int GetID() const { return m_nID; }
    };

    int Something::s_nIDGenerator;

    void load (int value) {
       Something::s_nIDGenerator = value;
    } 

};

int main() {
    using namespace test;
    load (1);

    Something cFirst;
    Something cSecond;
    Something cThird;

    using namespace std;
    cout << cFirst.GetID() << endl;
    cout << cSecond.GetID() << endl;
    cout << cThird.GetID() << endl;
    return 0;
}

对于“静态成员在一个类中而一个命名空间不起作用是怎么回事?”我仍然有点松散。这是怎么回事?为什么test::Something::s_nIDGenerator 不起作用? (仍然是我最初问题的一部分。)所以,到目前为止,我们只回答了一半。

我想知道为什么这不起作用,所以我不会再走进这个耙子。

【问题讨论】:

    标签: c++ object static namespaces initialization


    【解决方案1】:

    可能是因为您的friend int main() 声明是在声明命名空间还有一个免费的main() 函数,而真正的main() 函数不在命名空间中。

    修复它?首先在namespace test 之前(和外部)声明int main();,然后声明friend int ::main() 以表明它在全局命名空间中。

    更多详情请见this question

    【讨论】:

    • 虽然它可能有效,但让 ::main() 成为类的朋友并不是一个好主意。您最好在类内的函数中编写 ::main() 朋友代码,并从 ::main() 调用它。我的 2 美分。
    • @zmo 就是这样,谢谢!你给了我我需要的线索。将一个函数放在可以访问静态变量的类中。我厌倦了这个,它在我的测试示例和我的真实项目中都有效。 (仍然没有给我一个“为什么”......只是一个关于如何解决它的“什么”。我会将它作为答案发布,但如果有人可以解释这一点,我会标记一个“接受”。(显然我的学习材料不要把事情的“原因”讲得够多。)
    • 我猜你看不到它..... :(“糟糕!无法提交您的答案,因为:声誉低于 100 的用户无法回答他们自己的问题提问后 8 小时。您可以在 7 小时内自行回答。在此之前,请使用 cmets,或改为编辑您的问题。"
    • This: "7.3.1.2 命名空间成员定义第 3 段首先在命名空间中声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数 (这意味着类或函数的名称是不合格的)朋友类或函数是最内层封闭命名空间的成员。从那篇文章中可以看出原因。仔细观察,这就是为什么将其标记为私有的原因。这就是我的为什么。并不是说它无法通过名称访问,而是因为试图使用它的东西没有在适当的范围内声明。
    【解决方案2】:

    好吧,虽然我永远不会建议您像您在问题中所做的那样做,但这里是如何让您的代码“按原样”工作的方法:

    #include <iostream>
    
    int main(); // declare main beforehands so it can be seen by Something
    
    namespace test {   
        class Something {
        private:
                static int s_nIDGenerator;
                int m_nID;
                friend int ::main(); // take the main from global namespace
        public:
                Something() { m_nID = s_nIDGenerator++; }
                int GetID() const { return m_nID; }
        };
    };
    
    int test::Something::s_nIDGenerator;
    
    int main() {
        using namespace test;
        Something::s_nIDGenerator = 1; // tada that works
    
        Something cFirst;
        Something cSecond;
        Something cThird;
    
        using namespace std;
        cout << cFirst.GetID() << endl;
        cout << cSecond.GetID() << endl;
        cout << cThird.GetID() << endl;
        return 0;
    }
    

    但这里有一个友元函数的错误用例。我建议的似乎对您有用的解决方案(在您的类 Something 中使用函数)在可读性和可理解性方面要好得多。

    【讨论】:

    • 作为旁注,原因:当您执行“friend int main()”时,编译器认为您在 test 命名空间中声明了一个 main() 函数,该函数将在稍后定义(稍后在同一个对象中,或通过链接);然后它在真正的 main() 中抱怨您无权访问私有成员。
    • 当你执行 "friend int ::main()" 时,编译器会报错 "error: 'int main()' should have been declared inside '::'" 这意味着编译器从未听说过一个 "::main()" 无论如何,因为你从另一个命名空间中获取一个对象,并且你不能从一个命名空间声明新的原型到另一个命名空间,这就是为什么你需要声明 void main();
    • 我编辑了我原来的问题,你的版本有效,我看到 main 的前向声明。我尝试了您的想法(根据您的评论)。它确实有效。 (我也不喜欢我正在尝试做的事情......只是试图找到一个合理的解决方案。)你提出的想法也奏效了。命名空间内的类中的整个静态成员并不是那么严格。谢谢!!!!
    猜你喜欢
    • 2013-03-10
    • 2018-04-16
    • 2014-02-19
    • 2011-02-24
    • 2014-09-02
    • 2012-06-16
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多