美文网首页
C++命名空间和作用域限定符, since 2020-11-15

C++命名空间和作用域限定符, since 2020-11-15

作者: Mc杰夫 | 来源:发表于2020-11-15 15:31 被阅读0次

    (2020.11.15 Sun)

    C++命名空间namespace(ns)

    命名空间的引入是为了避免变量或函数重名的问题。

    C++中的名称(name)可以是符号常量、变量、宏、函数、结构、枚等。大规模程序设计中可能会出现标识符的命名发生冲突。解决办法是将变量定义在一个不同名字的命名空间中。

    命名空间有两种:有名与无名,他们的定义格式如下

    namespace 命名空间名 
    {声明序列}
    //有名
    namespace 
    {声明序列}
    //无名
    

    命名空间的成员可以在命名空间的定义内为其命名(内部定义),也可在命名空间外定义成员(外部定义)。但是不能再外部定义子命名空间

    namespace outer
    {
        int i;
        namespace inner  //子命名空间
        {
            void f() {i++;}
        }
        void f();
    }
    void outer::f() //在命名空间外部定义成员
    {
        i++;
    }
    
    • 命名空间只能定义在头文件中head file
    • 命名空间开放,可以随时更新加入新的成员
    //前面已经定义了outer
    namespace outer // 给命名空间outer加入新的成员
    {
        int k;
        void g() {
            printf('g');
        }
    }
    
    • 引用命名空间中的成员,使用作用域运算符::
    outer::k = 1;  //引用命名空间的成员并赋值时不需要指定数据类型
    
    • 在预编译部分中会出现include <iostream>和include <iostream.h>。在新的C++标准中,生成头文件的方法仅仅是将现有头文件名中的.h去掉。以前的C++头文件名.h会继续支持,但头文件的内容不在命名空间std中。新的头文件和旧文件相同,但是头文件的内容在命名空间std(一个类)中。因此调用std,即using namespace std前需要做预处理,即#include <iostream>,才可以使用std内的函数等内容。如果不调用std,not using namespace std,则在调用cin/cout时需要使用std::cin/cout。
    #include <iostream>
    using namespace std; //using编译指令
    int main() {
        cout << 'this is  a C++ p.' << endl;
        return 0;
    }
    //or
    #include <iostream>
    int main() {
        std::cout <<' this is also a C++ p.' << endl;
        return 0;
    }
    //或只使用命名空间的某个成员
    #include <iostream>
    using outer::g; //using声明,针对命名空间中名称的使用
    void main () {
        g(); //调用outer的g成员
    }
    
    • 上面的例子中有using namespace outer和using outer::g两种用法,前一种称为using编译指令,后一种称为using声明。声明只把ns中特定成员的名称添加到所在的区域,使得该成员可以不需要采用命名空间的作用域解析运算符来定位,而直接被使用。但是使用using声明更安全,因其只会导入指定的名称。如果该名称与局部名称发生冲突,则编译器会报错。而using指令导入整个ns中所有成员的名称,如果其中有名称与局部名称发生冲突,编译器不会报错,只是用局部名称自动覆盖ns中的同名成员。当需要反复使用一个ns中的多个函数时,使用using编译指令;当只需要使用一个ns中的特定几个函数时,建议使用ns声明。

    (2020.11.17 Tues)

    命名空间和类的区别

    一般程序的开发都由多人完成,为防止不同模块的类和函数重名,采用命名空间来区分避免混淆。

    只要两个类在不同的命名空间中,他们就可以拥有相同的类名称。把类封装进命名空间的优势在于方便调用甚至其他应用程序的调用。

    #include <iostream>
    using namespace std;
    namespace s1
    {
        class S_Class
            {
            public:
                void show() 
                {
                    cout << '调用命名空间S1中类S_Class的函数show().' << endl;
                }
            };
    }
    namespace s2
    {
        class S_Class
        {
        public:
            void show()
            {
                cout << '调用命名空间s2的类S_Class的函数show()' << endl;
            }
        };
    }
    int main() {
        s1::S_Class x; //声明一个s1中类S_Class的实例x
        x.show(); //调用类实例x中的show(),输出结果
        s2::S_Class y; //声明一个s2中类S_Class的实例y
        y.show(); //调用类实例y中的show(),输出结果
        return 0;
    }
    

    作用域限定符Scope resolution operator ::

    在三种情况中使用作用域限定符

    • 命名空间的使用过程中,使用::来引用指定命名空间中的成员。另一种引用方法是使用using指令。
    • 在不同作用域内声明的变量可以重名,但如果局部变量和全局变量重名,在局部变量的作用域内可以使用::来引用全局变量
    #include <iostream>
    using namespace std;
    int x = 100; //定义全局变量
    int main ()
    {  
        int x = 150;
        cout << '全局变量x=' << ::x << endl; //输出全局变量
        cout << '局部变量x=' << x << endl; //输出局部变量
        ::x = 750;
        cout << '全局变量x=' << ::x << endl; //输出全局变量
        cout << '局部变量x=' << x << endl; //输出局部变量
        return 0;
    }
    

    另外,::只能用来访问全局变量,不能访问一个在语句块外生命的同名局部变量。下面是一个错误的使用方式。

    //这是一个错误的使用方式
    void main() {
        int x = 11; //x是局部变量
        {
            int x = 22;
            ::x = 33; //错误的修改方式,因x也是局部变量
        }
    }
    
    • 在类外定义类成员函数时,需要使用scope resolution operator。比如声明一个类A,里面声明了一个成员函数void fun();,如果类中没有给出该成员定义,在类外定义该成员时,要写成void A::fun(),表示函数fun()是类A的成员函数。
    #include <iostream>
    #include <string.h>
    class cbook
    {
        private:
            char * m_pczname;
            int m_npages;
            int m_nedition;
        public:
            void getbookname(char *pname);
            int getbookedition();
        private:
            void setbookname(char * pname);
            void settotalpages(int npages);
        public:
            cbook();
    }; //定义一个类和结构体的结尾处的大括号后面有个分号
    void cbook::getbookname(char * pname)
    {
        strcpy(pname, m_pczname); //定义成员函数
    }
    int cbook::getbookedition()
    {
        return m_nedition; //成员函数中引用类成员变量,直接写名字,不需要加self
    }
    void cbook::setbookname(char * pname)
    {
        if (m_pczname != 0)
            delete[] p_pczname;
        m_pczname = new char[strlen(pname)+1]; //重新分配存储空间
        strcpy(m_pczname,pname); //复制字符串
    }
    void cbook::settotalpages(int npages)
    {
        m_npages = npages; //成员函数中引用类成员变量,直接写名字,不需要加self
    }
    void main ()
    {
        cbook op1; //声明该类的对象
        int i;
        i = op1.getbookedition();
        cout << i << endl;
    }
    

    这里注意到,类说明的程序内容较多,应该放在独立的文件中。例如cbook的类说明可以放在头文件xxx.h中,类的定义放在以.cpp为扩展名的文件中,称为类的实现文件。在文件开始部分应该用include将类说明文件包含进来(类实现可以不include?)

    Reference

    1 刘蕾编著,21天学通C++,中国工信出版集团,电子工业出版社
    2 聚慕课教育研发中心编著,C++从入门到项目实践(超值版),清华大学出版社

    相关文章

      网友评论

          本文标题:C++命名空间和作用域限定符, since 2020-11-15

          本文链接:https://www.haomeiwen.com/subject/egmnbktx.html