Functions may be nested within other functions:
int bar(int a)
{
int foo(int b)
{
int abc() { return 1; }
return b + abc();
}
return foo(a);
}
void test()
{
int i = bar(3); // i is assigned 4
}
Nested functions can only be accessed by the most nested lexically enclosing function, or by another nested function at the same nesting depth:
int bar(int a)
{
int foo(int b) { return b + 1; }
int abc(int b) { return foo(b); } // ok
return foo(a);
}
void test()
{
int i = bar(3); // ok
int j = bar.foo(3); // error, bar.foo not visible
}
Nested functions have access to the variables and other symbols defined by the lexically enclosing function. This access includes both the ability to read and write them.
int bar(int a)
{ int c = 3;
int foo(int b)
{
b += c; // 4 is added to b
c++; // bar.c is now 5
return b + c; // 12 is returned
}
c = 4;
int i = foo(a); // i is set to 12
return i + c; // returns 17
}
void test()
{
int i = bar(3); // i is assigned 17
}
This access can span multiple nesting levels:
int bar(int a)
{ int c = 3;
int foo(int b)
{
int abc()
{
return c; // access bar.c
}
return b + c + abc();
}
return foo(3);
}
Static nested functions cannot access any stack variables of any lexically enclosing function, but can access static variables. This is analogous to how static member functions behave.
int bar(int a)
{ int c;
static int d;
static int foo(int b)
{
b = d; // ok
b = c; // error, foo() cannot access frame of bar()
return b + 1;
}
return foo(a);
}
Functions can be nested within member functions:
struct Foo
{ int a;
int bar()
{ int c;
int foo()
{
return c + a;
}
}
}
Member functions of nested classes and structs do not have access to the stack variables of the enclosing function, but do have access to the other symbols:
void test()
{ int j;
static int s;
struct Foo
{ int a;
int bar()
{ int c = s; // ok, s is static
int d = j; // error, no access to frame of test()
int foo()
{
int e = s; // ok, s is static
int f = j; // error, no access to frame of test()
return c + a; // ok, frame of bar() is accessible,
// so are members of Foo accessible via
// the 'this' pointer to Foo.bar()
}
}
}
}
A function pointer can point to a static nested function:
int function() fp;
void test()
{ static int a = 7;
static int foo() { return a + 3; }
fp = foo;
}
void bar()
{
test();
int i = fp(); // i is set to 10
}
A delegate can be set to a non-static nested function:
int delegate() dg;
void test()
{ int a = 7;
int foo() { return a + 3; }
dg = foo;
int i = dg(); // i is set to 10
}
The stack variables, however, are not valid once the function declaring them has exited, in the same manner that pointers to stack variables are not valid upon exit from a function:
int* bar()
{ int b;
test();
int i = dg(); // error, test.a no longer exists
return &b; // error, bar.b not valid after bar() exits
}
Delegates to non-static nested functions contain two pieces of data: the pointer to the stack frame of the lexically enclosing function (called the frame pointer) and the address of the function. This is analogous to struct/class non-static member function delegates consisting of a this pointer and the address of the member function. Both forms of delegates are interchangeable, and are actually the same type:
struct Foo
{ int a = 7;
int bar() { return a; }
}
int foo(int delegate() dg)
{
return dg() + 1;
}
void test()
{
int x = 27;
int abc() { return x; }
Foo f;
int i;
i = foo(abc); // i is set to 28
i = foo(f.bar); // i is set to 8
}
This combining of the environment and the function is called a dynamic closure.
Operator Overloading
Overloading is accomplished by interpreting specially named member functions as being implementations of unary and binary operators. No additional syntax is used.
Unary Operator Overloading
op
|
opfunc
|
-
|
neg
|
~
|
com
|
e++
|
postinc
|
e--
|
postdec
|
Given a unary overloadable operator op and its corresponding class or struct member function name opfunc, the syntax:
op a
where a is a class or struct object reference, is interpreted as if it was written as:
a.opfunc()
Overloading ++e and --e
Since ++e is defined to be semantically equivalent to (e += 1), the expression ++e is rewritten as (e += 1), and then checking for operator overloading is done. The situation is analogous for --e.
Examples -
class A { int neg(); }
-
A a;
-
-a; // equivalent to a.neg();
-
-
class A { int neg(int i); }
-
A a;
-
-a; // equivalent to a.neg(), which is an error
-
Share with your friends: |