D programming Language



Download 1.66 Mb.
Page20/47
Date08.01.2017
Size1.66 Mb.
#7507
1   ...   16   17   18   19   20   21   22   23   ...   47

Nested Functions


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()

}

}

}



}


Delegates, Function Pointers, and Dynamic Closures


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

Overloadable Unary Operators


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


  1. class A { int neg(); }

  2. A a;

  3. -a; // equivalent to a.neg();



  4. class A { int neg(int i); }

  5. A a;

  6. -a; // equivalent to a.neg(), which is an error




Download 1.66 Mb.

Share with your friends:
1   ...   16   17   18   19   20   21   22   23   ...   47




The database is protected by copyright ©ininet.org 2024
send message

    Main page