UnigineEditor
Interface Overview
Assets Workflow
Settings and Preferences
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Landscape Tool
Using Editor Tools for Specific Tasks
FAQ
编程
Fundamentals
Setting Up Development Environment
Usage Examples
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
应用程序接口
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
CIGI Client Plugin
Rendering-Related Classes

Scope. Namespaces

Scope(作用域)#

Scope决定某种在程序中进行使用的标识符在程序中的可访问区域,这种标识符可以是一个变量,一种枚举类型,一种函数,一个类,一个命名空间等。

注意
对于变量,作用域决定了着其可访问性及生命期,而生命期并受当前作用域的限制(具体细节信息请参看下列内容)。

作用域范围的大小取决于声明标识符的地点。例如如果在某个类的顶端位置处声明了一个变量,那么此变量的作用域便是整个类中的所有方法所涉及的范围。但如果在某个方法中声明了一个变量,那么此变量的作用域范围仅限于此方法的作用域范围内。

使用一组花括号({}) 定义一个新的作用域。

例如:

源代码 (UnigineScript)
namespace Foo {
    int a = 10;
}
int a = 5;
log.message("Foo::a is %d, a is %d", Foo::a,a);
输出
Foo::a is 10, a is 5

如果在所有模块的外部使用花括号封装并声明一个标识符,那么此标示符的作用域为全局范围。这就是说声明此标识符后可在程序中的任意位置处访问此标识符。

注意
如果某种函数并未类的成员并在所有模块外部进行声明,那么同样此函数的作用域为全局范围。
例如:
源代码 (UnigineScript)
// foo()方法的作用域为全局范围
int foo() { log.message("Function in the global scope\n"); }

class Foo {
    Foo (){}
    // foo() 方法的作用域仅限Foo类的范围
    int foo(){ log.message("Class member function\n"); }
};

如上所述,变量的生命期并不受当前范围的限制。换句话说即本地变量的生命期与全局变量的生命期相同(除非 另有 注明)。例如:

源代码 (UnigineScript)
int foo() {
    int local_var;
    local_var++;
    log.message("local_var: %d\n",local_var);
}

foo(); // local_var: 1
foo(); // local_var: 2
这种情况下,local_var的变量生命期并不受foo()范围的限制。因此在第二次调用foo()时,先前调用得到的值会增加。用C++的话说就是,其与使用静态修饰符声明的变量相似。

如果要对变量local_var的局部生命期进行仿真,应以如下方式对此变量进行初始化:

源代码 (UnigineScript)
int foo() {
    int local_var = 0;
    local_var++;
    log.message("local_var: %d\n",local_var);
}

foo(); // local_var: 1
foo(); // local_var: 1

作用域解析运算符#

作用域解析运算符::被用来指定运算符涉及的语境。也可使用此运算符来访问命名空间外的变量,类作用域外的函数或者处理某个标识符的作用域。使用此标识符来表述全局变量及类中的成员。

通过::为函数(变量,类,命名空间等)名增加一个前缀,指定使用全局范围的函数。这样可以确保范围解析将从全局范围开始而不从当前范围开始。例如:

源代码 (UnigineScript)
namespace Test {
    int a;
    void info() { log.message("a from the scope of the 1st namespace is %d\n",a); }
}

int init () {

    namespace Test {
        int a;
        void info() { log.message("a from the scope of the 2nd namespace is %d\n",a); }
    }
	// 访问全局命名空间的成员
    ::Test::a = 10;
    ::Test::info();
	
	// 访问在当前作用域内声明的命名空间成员
    Test::a = 30;
    Test::info();

    return 1;
}
输出结果如下:
输出
a from the scope of the 1st namespace is 10 
a from the scope of the 2nd namespace is 30

注意
UnigineScript函数库中的函数具有全局作用域。因此如果函数名被再次用来在其它域内定义用户函数,::运算符可以确保UnigineScript库中函数为全局解析范围。

假设用户自定义类中某个函数的函数名与UnigineScript库中某个函数名相同。 要在用户自定义函数的作用域范围内调用原始UnigineScript函数,将 :: 运算符作为函数的前缀添加到函数名称前。 例如:

源代码 (UnigineScript)
class Foo {
    Foo() {}

    // 在Foo类解析范围内的用户自定义函数
    void rotate(float angle) {
        // UnigineScript函数用来获取按照所给角度围绕轴旋转的矩阵 
        mat4 rot = ::rotate(vec3(1.0f, 0.0f, 0.0f), angle);
    }
};
如果未指定::运算符,解析器会在控制台中输出如下内容:
源代码
NameSpace::getFunctionID(): can't find "rotate" function with 2 arguments

命名空间#

Namespaces可对诸如类,对象及函数名称实体进行分组。全局作用域可被分成子作用域,每个子作用域具有其自己的名称。

命名空间的格式为:

源代码 (UnigineScript)
namespace identifier {
	// 实体
}

定义命名空间的示例:

源代码 (UnigineScript)
namespace Foo {
	int a = 10;
}
int a = 5;
log.message("Foo::a is %d, a is %d", Foo::a,a);

// 输出: Foo::a is 10, a is 5

也可使用using关键字将命名空间的名称引入当前声明区域。

源代码 (UnigineScript)
namespace Foo::Bar {
	int a = 10;
}

void foo() {
	using Foo::Bar;
	log.message("Foo::Bar::a is %d\n",a);
}
foo();

// 输出: Foo::Bar::a is 10
最新更新: 2017-07-03