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

(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 和include 。在新的C++标准中,生成头文件的方法仅仅是将现有头文件名中的.h去掉。以前的C++头文件名.h会继续支持,但头文件的内容不在命名空间std中。新的头文件和旧文件相同,但是头文件的内容在命名空间std(一个类)中。因此调用std,即using namespace std前需要做预处理,即#include ,才可以使用std内的函数等内容。如果不调用std,not using namespace std,则在调用cin/cout时需要使用std::cin/cout。
#include 
using namespace std; //using编译指令
int main() {
    cout << 'this is  a C++ p.' << endl;
    return 0;
}
//or
#include 
int main() {
    std::cout <<' this is also a C++ p.' << endl;
    return 0;
}
//或只使用命名空间的某个成员
#include 
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 
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 
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 
#include 
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)