C # vs C ++: Delegate vs function pointer

Source: Internet
Author: User

Analysis of delegation and function pointer

We often use C # technical documents to introduce delegation with "something similar to C/C ++ function pointers. This seems to make sense, because the two do have deep-seated similarities. Both the delegate and function pointer describe the method/function signature and call different implementations through a unified interface. However, the two have obvious differences. Simply put, the delegate object is the real object, and the function pointer variable is only the function entry address. For high-level applications, the flexibility and applicability of delegation are better than function pointers. However, for underlying applications, function pointers are irreplaceable. The following are examples of delegate type and function pointer type definitions:

Delegate int Fn (int a, int B) // C # delegate

Typedef int (* Fn) (int a, int B) // C ++ function pointer

In terms of form, both the parameter list and return values are the same, but one uses the keyword delegate and the other uses the pointer symbol *. It seems that the "similar" statement is more confident, but it would be too urgent if the two are immediately given an equal sign. Let's verify the difference first:

// C #

Delegate int Fn (int a, int B );

Class Adder {

Private int c = 0;

Public int Add (int a, int B ){

Return a + B + c;

}

Public Adder (int c) {this. c = c ;}

}

Class Multiplier {

Private int c = 0;

Public int Multiple (int a, int B ){

Return a * B * c;

}

Public Multiplier (int c) {this. c = c ;}

}

Adder adder = new Adder (1 );

Multiplier multiplier = new Multiplier (2 );

Fn fn = adder. Add;

Fn (1, 2); // The result is 4

Fn = multiplier. Multiple;

Fn (2, 3); // The result is 12

The code above illustrates two problems:

1. The delegate object can point to different classes of methods, as long as they comply with the delegate signature;

2. The delegate object is stateful (stored in the object to which it points). The delegate behavior is not only affected by the input parameters, but also by the status of the target object.

// C ++

Typedef int (* Fn) (int a, int B );

Int Add (int a, int B ){

Return a + B;

};

Int Multiple (int a, int B ){

Return a * B;

};

Class Adder {

Public:

Adder (int c ){

This-> c = c;

}

Int Add (int a, int B ){

Return a + B + c;

}

Private:

Int c;

};

Typedef int (Adder: * Fm) (int a, int B );

Int _ tmain (int argc, _ TCHAR * argv [])

{

Fn fn = Add;

Std: cout <fn (1, 2) <std: endl;

Fn = Multiple;

Std: cout <fn (1, 2) <std: endl;

Adder adder (1 );

Fm f = & Adder: Add;

Std: cout <(adder. * f) (1, 2) <std: endl;

Return 0;

}

The delegate in C # is a special object that supports the () operator. This is essentially different from the function pointer of C/C ++, because the function pointer variable of C/C ++ is not of the object nature, and it is just the function entry address. The above Fn can only point to the Add and Multiple common functions, and cannot point to the Add method of the Adder class. Because the signature of the Add method of the Adder class is not int (*) (int a, int B), the compiler automatically adds an implicit this pointer parameter, therefore, its signature is similar to int (*) (Adder * const this, int a, int B. If you want to direct the pointer to a member function, you need to add a type qualifier in the form of typedef int (Adder: * Fm) (int a, int B. Therefore, the C ++ function pointer cannot direct to different classes of methods like the C # Delegate; it does not have the State nature of the object; in use, the function pointer is not as flexible as the delegate. Therefore, when we hear the saying "delegate is similar to the C/C ++ function pointer", we should understand its similarities and differences.

Functor

We often say that C ++ is a powerful and complex language, and function pointers have been entrusted to PK by C #. Isn't C ++ a general engineer who can entrust pk c? Of course! First, we should see that the function pointer is not a product of C ++, but inherited from C. Therefore, the limitation of the function pointer is actually the limitation of C and has nothing to do with C ++. C # delegate is a special object that supports () function call operators. In C ++, the () operator can be overloaded () the object of the operator is called functor. The following is an example of functor:

Class Adder {

Public:

Adder (int c ){

This-> c = c;

}

Int operator () (int a, int B ){

Return a + B + c;

}

Private:

Int c;

};

Int _ tmain (int argc, _ TCHAR * argv []) {

Adder adder (1 );

Std: cout <adder (2, 3) <std: endl; // output 6, adder is the functor-object with the () operator reloaded

Return 0;

}

Similar to a delegate object, functor is a stateful object that supports the () operator. But functor is not commissioned. Why? Because the delegate type is an interface specification, and the function pointer type is also, functor itself is not an interface specification. Note the relationship between types and objects: Delegate type and delegate object, function pointer type and function pointer variable. Functor can be equivalent to a delegate object, but how does one express the delegate type? It should be seen that the delegation mechanism is a kind of dynamic polymorphism during runtime, and the delegate object can be dynamically bound to the target method. Since C ++ is not a virtual machine-based language, it is not easy to dynamically bind different types of functor to a unified type interface. However, C ++ has a powerful tool for static polymorphism, which is a template:

Template

Class Adder {

Public:

Adder (int c ){

This-> c = c;

}

Int operator () (int a, int B ){

Return a + B + c;

}

Private:

Int c;

};

Class Multiplier {

Public:

Multiplier (int c ){

This-> c = c;

}

Int operator () (int a, int B ){

Return a * B * c;

}

Private:

Int c;

};

 

Template <typename T>

Void Do (T & f, int a, int B ){

Int r = f (a, B );

Std: cout <r <std: endl;

};

Int _ tmain (int argc, _ TCHAR * argv []) {

Adder adder (1 );

Do (adder, 1, 2); // output 4

Multiplier multiplier (10 );

Do (multiplier, 2, 3); // output 60

Return 0;

}

The function template Do expresses the interface specification. It requires a generic class T to support the () operator, accept two integer parameters, and return a type that can be implicitly converted to the int type. For different types of Adder and Multiplier, the compiler automatically generates different Do overload functions for different types of T according to the template during compilation, so the Do call form is unified, this is the so-called static polymorphism. Some people have mentioned that "the static type of the template gives almost no type of meta-programming capability". This example is a small peek. Many library methods in STL Use templates to express interface specifications. Callers pass in functor, and their flexibility is completely free from C # delegation.

Summary

1. C # The delegate object is a real object, and the C/C ++ function pointer is only the function entry address.

2. Delegate object of C ++: functor

3. Static polymorphism of C ++: Template

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.