10 C # errors that C ++ programmers can easily make
Source: Internet
Author: User
10 C # errors that C ++ programmers can easily make-Linux general technology-Linux programming and kernel information. The following is a detailed description. We know that the syntax of C # is very similar to that of C ++. The difficulty of the transformation from C ++ to C # lies not in the language itself, but in familiarity.. NET manageable Environment and. NET Framework. Although the syntax changes of c # And C ++ are very small, they will hardly affect us, but some changes are enough to keep some careless C ++ programmers in mind. In this article, we will discuss the ten mistakes that C ++ programmers are most likely to make.
Trap 1: There is no clear end Method
For most C ++ programmers, the biggest difference between C # And C ++ is fragment collection. This also means that programmers no longer have to worry about memory leaks and ensure that all useless pointers are deleted. But we can no longer precisely control the process of killing useless objects. In fact, there is no clear destructor in C.
If you use non-manageability resources, you must release them explicitly after they are not used. Implicit control over resources is provided by the Finalize method (also known as finalizer). When an object is destroyed, it is called by the fragment collection program to reclaim the resources occupied by the object. Finalizer should only release non-manageability resources occupied by destroyed objects, and should not involve other objects. If only manageability resources are used in the program, the Finalize method is not required and should not be executed. The Finalize method is only used in the process of non-manageability resources. Because the finalizer occupies a certain amount of resources, you should only execute finalizer in the method that requires it. Directly calling the Finalize method of an object is absolutely not allowed (unless the Finalize of the basic class is called in the Finalize of the subclass .), The fragment collector automatically calls Finalize.
In terms of syntax, the destructor in C # is very similar to C ++, but they are actually completely different. The destructor in C # is just a shortcut to define the Finalize method. Therefore, the following two pieces of code are different:
~ MyClass ()
{// Task to be completed
}
MyClass. Finalize () {// task to be completed
Base. Finalize ();
}
Error 2: Who is used by Finalize and Dispose?
From the above discussion, we know that explicit calls to finalizer are not allowed, and it can only be called by the fragment collection program. If you want to release a limited number of non-manageability resources (such as file handles) that are no longer in use as soon as possible, you should use the IDisposable interface, which has a Dispose method, it can help you complete this task. Dispose is a method that can release non-manageability resources without waiting for Finalize to be called.
If the Dispose method is used, the fragment collection program should be prevented from executing the Finalize method on the corresponding object. Therefore, you need to call the Static Method GC. SuppressFinalize and pass the pointer of the corresponding object to it as a parameter. The Finalize method can call the Dispose method. Accordingly, we can get the following code:
Public void Dispose ()
{
// Complete the cleanup operation
// Notify GC not to call the Finalize method again
GC. SuppressFinalize (this );
}
Public override void Finalize (){
Dispose (); base. Finalize ();
}
For some objects, it is more appropriate to call the Close method (for example, it is more appropriate to call Close for object objects than Dispose ), you can create a Dispose method for the private attribute and a Close method for the public attribute, and call Dispose to call the Close method for some objects.
Dispose is always called, and the execution of finalizer is also uncertain (we cannot control when the GC will run ), C # provides a Using statement to ensure that the Dispose method is called as early as possible. The general method is to define which object to use, and then use parentheses to specify an activity range for these objects. In the case of the innermost parentheses, the Dispose method will be automatically called, process the object.
Using System. Drawing;
Class Tester
{
Public static void Main ()
{
Using (Font theFont = new Font ("Arial", 10.0f ))
{
// Use theFont object
} // The compiler will call Dispose to process theFont objects
Font anotherFont = new Font ("Courier", 12.0f );
Using (anotherFont)
{
// Use the anotherFont object
} // The compiler will call Dispose to process the anotherFont object}
}
In the first part of this example, the Font object is created in the Using statement. When the Using statement ends, the system calls Dispose to process the Font object. In the second part of this example, the Font object is created outside the Using statement. When you decide to use it, place it in the Using statement. When the Using statement ends, the system will call Dispose. The Using statement can also prevent other accidents and ensure that the system will call Dispose.
Error 3: The value variables in C # are different from the referenced variables.
Like C ++, C # is also a strong programming language. Data Types in C # are classified into two categories: the data types inherent in C # language and user-defined data types, which are similar to C ++.
In addition, the C # Language divides variables into value type and reference type. Unless it is included in a reference type, the value of the value type variable is kept in the stack, which is very similar to the variable in C ++. The reference type variable is also a type of stack, and its value is the address of the object in the heap, which is very similar to the pointer in C ++. The value of a value type variable is passed directly to the method. When a referenced variable is passed as a parameter to the method, the index is passed. Class and interface can create reference class variables, but it should be noted that the structure data type is a built-in data type of C # and also a value type.
Error 4: Implicit data type conversion
Boxing and unboxing are two processes used to make the value data type be used as the index data type. A value variable can be encapsulated into an object and then unwrapped back to the value variable. Data Types in C #, including built-in data types, can be implicitly converted into an object. Wrap a value-type variable to generate an object instance, and then copy the variable to the instance.
Boxing is implicit. If a variable of the value data type is used where the index data type is required, the value variable is implicitly converted to the variable of the index data type. Boxing will affect the performance of code execution, so we should avoid it as much as possible, especially when the data volume is large.
To convert a packaged object back to the original value type variable, you must unpackage it explicitly. Two steps are required for unpacking: First, check the object instances to ensure that they are packaged by value variables; second, copy the values in the instances to the value variables. To ensure successful unpacking, the unwrapped object must be the index of the object generated by packing the value of a value-type variable.
Using System;
Public class UnboxingTest
{
Public static void Main ()
{
Int I = 123; // package
Object o = I; // unpack (must be explicit)
Int j = (int) o;
Console. WriteLine ("j: {0}", j );}
}
If the unwrapped object is invalid or the index of an object of different data types, the InvalidCastException will occur.
Error 5: The structure and object are different.
The structure in C ++ is similar to the class. The only difference is that, by default, the structure access permission is public, and its inherited permission is public. Some C ++ programmers use structures as data objects, but this is only a convention, not a necessity. In C #, the structure is only a user-defined data type and cannot replace classes. Although the structure also supports attributes, methods, fields, and operators, inheritance and destructor are not supported.
More importantly, the class is an index-type data type, and the structure is a value-type data type. Therefore, the structure is more useful in expressing objects without indexing operations. The structure is more efficient in Array Operations, but less efficient in the collection operations. The set needs to be indexed, and the structure must be packaged for use in the set operation. Classes are more efficient in large-scale set operations.
Error 6: The virtual method must be explicitly overwritten.
In C #, programmers must explicitly use the override parameter when overwriting a virtual method. Assume that A Window class is compiled by Company A. The ListBox and RadioButton classes are written by Company B and programmers Based on the Window class prepared by Company, company B's programmers know little about the design, including the future changes of the Window class. If a programmer from Company B wants to add an Sort method to ListBox:
Public class ListBox: Window
{Public virtual void Sort (){"}
}
This is not A problem before Company A releases the new Window class. If Company A's programmers add an Sort method to the Window class.
Public class Window
{// "Public virtual void Sort (){"}
}
In C ++, the Sort method in the Windows class will become the basic method of the Sort method in The ListBox class. When you want to call the Sort method in the Windows class, the Sort method in The ListBox class is called. In C #, virtual functions are always considered as the root of virtual scheduling. That is to say, once C # discovers a virtual method, it will no longer find other virtual methods in the virtual chain. If the ListBox is compiled again, the compiler generates a warning message:
To overwrite the current member to the original method, you need to add the override or the new one.
To eliminate the warning information, the programmer must understand what he wants. You can add new before the Sort method in The ListBox class, indicating that it should not overwrite the virtual method in the Window:
Public class ListBox: Window {
Public new virtual void Sort (){"}
In this way, the warning information can be cleared. If programmers really want to overwrite the methods in the Window, they must use override to explicitly indicate their intent.
Error 7: class member variable Initialization
The initialization in C # is different from that in C ++. Assume that there is a Person class with a private member variable age. The Employee is generated by inheriting the Person class and has a private salaryLevel member variable. In C ++, We can initialize salaryLevel in the initialization part of the constructor of the Employee, as shown in the following code:
Employee: Employee (int theAge, int theSalaryLevel ):
Person (theAge) // initialize the basic class
SalaryLevel (theSalaryLevel) // initialize the member variable
{
// Constructor code
}
This method is invalid in C. Although the basic class can still be initialized, initialization of member variables like the above Code will cause compilation errors. In C #, We can initialize a member variable while defining it:
Class Employee: public Person
{// Member variable definition
Private salaryLevel = 3; // Initialization
}
Note: The access permission for each variable must be clearly defined.
Error 8: Boolean variables and integer variables are different.
If (someFuncWhichReturnsAValue ())
In C #, the Boolean variable is different from the integer variable, so the following code is incorrect:
If (someFuncWhichReturnsAValue ())
If someFuncWhichReturnsAValue returns zero, which indicates false. Otherwise, the idea of true is no longer feasible. The advantage is that the original mistake of obfuscation of the assignment operation and equality will not be committed again. So the following code:
If (x = 5)
An error occurs during compilation, because x = 5 only assigns 5 to X, not a Boolean value.
Error 9: some statements cannot be executed in the switch statement.
In C #, if a switch statement executes some operations, the program may not be able to execute to the next statement. Therefore, although the following code is valid in C ++, it is invalid in C:
Switch (I)
{
Case 4:
CallFuncOne (); case 5: // error, not executed here
CallSomeFunc ();
}
To achieve the purpose of the above Code, you need to use a goto statement:
Switch (I)
{
Case 4: CallFuncOne ();
Goto case 5; case 5:
CallSomeFunc ();
}
If the case statement does not execute any code, all statements will be executed. The following code:
Switch (I)
{
Case 4: // can be executed to case 5: // can be executed
Case 6: CallSomeFunc ();
}
Error 10: variables in C # Must be explicitly assigned values.
In C #, all variables must be assigned a value before use. Therefore, you can not initialize a variable when defining it. If you pass it to a method, it must be assigned a value.
If you only pass a variable to the method through the index and the variable is the output variable of the method, this will cause problems. For example, suppose there is a method that returns the hour, minute, and second of the current time. If you write code like the following:
If the three variables theHour, theMinute, and theSecond are not initialized, a compilation error is generated:
Use of unassigned local variable 'theur'
Use of unassigned local variable 'theminute'
Use of unassigned local variable 'thesecond'
We can solve this small problem of the compiler by initializing these variables to 0 or other values that have no impact on the return value of the method:
In this way, these variables are passed to the GetTime method and then changed. To solve this problem, C # provides the out parameter modifier specifically for this situation, which allows a parameter to be referenced without initialization. For example, parameters in GetTime have no meaning for themselves, but they are only used to express the output of this method. Before returning results in a method, the Out parameter must be specified with a value. The modified GetTime method is as follows:
Public void GetTime (out int h, out int m, out int s ){
H = Hour;
M = Minute;
S = Second;
}
The following describes how to call the new GetTime method:
TimeObject. GetTime (out theHour, out theMinute, out theSecond );
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.