C ++ learning 5. Understanding C ++ Problems

Source: Internet
Author: User

 

Understanding C ++ Problems

 

1. Reference

 

Professional C ++ code is heavily referenced. The reference of C ++ is the alias of another variable. Changes to the reference will change the value of the variable pointed to by the reference. You can regard reference as an implicit pointer, which saves the trouble of getting the variable address and removing the reference from the pointer. You can also regard reference as another name of the original variable. You can create independent reference variables, use referenced data members in the class, accept parameters passed to functions and methods, and return references from functions and methods.

 

(1). Reference variable: It must be initialized at creation.

 

Int x = 3;

 

Int & xRef = x;

 

XRef = 10; // change the value of x to 10.

 

If the referenced variable declared outside the class is not initialized, this is not allowed.

 

Int & yRef; // error

 

It must be initialized when a reference is assigned. Generally, references are allocated in the declaration, but the referenced data member can be initialized in the initialization list of the class containing the member.

 

You cannot create a reference pointing to an unnamed value unless the reference points to a const value.

 

Int & unnameRef = 5; // error

 

Const int & unnameRef = 5; OK

 

The reference always points to the variable specified during initialization. Once a reference is created, it cannot be modified.

 

Int x = 3, y = 5;

 

Int & xRef = x;

 

XRef = y; // The xRef reference does not point to y, but still points to x, but the value of x is changed to 5 of y.

 

You may want to take the address of y to bypass this restriction when assigning values:

 

Int x = 3, y = 5;

 

Int & xRef = x;

 

XRef = & y; // error. The address of y is a pointer, and xRef is a reference to the int variable, not a reference to the pointer.

 

What will happen below?

 

Int x = 3, y = 5;

 

Int & xRef = x;

 

Int & yRef = y;

 

XRef = yRef; // The xRef reference does not point to y, but still points to x, but the value of x is changed to 5 of y.

 

To sum up, the reference cannot be modified after initialization but points to another variable. It can only modify the value of the variable to which it points.

 

 

 

Pointer Reference and reference pointer:

 

The following is an example of a reference to an int pointer.

 

Int * intP;

 

Int * & ptrRef = intP

 

PtrRef = new int;

 

* PtrRef = 5;

 

Note: Get the referenced address and the address of the variable pointed to by the reference. The results are the same.

 

Int x = 3;

 

Int & xRef = x;

 

Int * xPtr = & xRef; // equivalent to int * xPtr = & x

 

* XPtr = 100;

 

Note: you cannot declare a reference or a reference pointer ).

 

Int x = 3;

 

Int & xRef = x;

 

Int & doubleRef = xRef; // error

 

Int & * refPtr = & xRef; // error

 

 

 

(2). Reference data members:

 

The data member of the class can be a reference. However, if the reference does not point to another variable, such a reference cannot exist. Therefore, you must initialize the referenced data member in the constructor initialization list, instead of completing the initialization in the constructor body.

 

 

 

(3). Reference parameters:

 

C ++ does not often use independent variables or reference data members. The most common usage of reference is as a parameter of functions and methods.

 

Void swap (int & first, int & second)

 

{

 

Int temp = first;

 

First = second;

 

Second = temp;

 

}

 

However, the following functions do not work.

 

Void swap (int first, int second)

 

{

 

Int temp = first;

 

First = second;

 

Second = temp;

 

}

 

We know that constants cannot be used to initialize referenced variables. Similarly, constants cannot be passed as real parameters to functions with reference passed as parameters.

 

Swap (3, 5); // error

 

Reference from pointer: If you pass a pointer to a function or method, what this function or method requires is a reference. In this case, the pointer is simply removed from the reference to convert the pointer into a reference.

 

Int x = 3, y = 5;

 

Int * xp = & x, * yp = & y;

 

Swap (* xp, * yp );

 

Pass value and reference:

 

If you want to modify parameters and want these modifications to be reflected in the real variable of a function or method, you should transmit the reference. However, it should not be limited to transferring references only in this case. Transferring a reference can avoid copying the real parameters of a function. In some cases, this can bring two benefits:

 

A. efficiency. It may take a long time to copy large objects and structures. Only a pointer pointing to an object or structure is passed to a function or method.

 

B. correctness. Not all objects are allowed to pass values. Even if values are allowed, deep replication is not supported. We know that to support deep replication, custom replication constructor must be provided for objects with dynamically allocated memory.

 

If you want to take advantage of these two advantages and do not want to change the original object, you can add the const in front.

 

The advantages of passing references mean that for simple built-in types, you should use passing values without modifying real parameters. In other cases, you can consider transferring references.

 

 

 

(4). Reference return type:

 

Returns a reference from a function or method. The main reason for this is the efficiency. Instead of returning a complete object, it returns a reference to the object from a function or method, so as to avoid unnecessary replication. Of course, this technology can only be used if the current object still exists after the function or method ends.

 

Note: It is necessary to return the reference of the variable created on the stack in the function or method. Because the function or method will cancel these variables at the end. Will the variables allocated to the stack in the function be revoked at the end of the function?

 

 

 

(5). Use reference or pointer:

 

References in C ++ are probably redundant. References can be done, and almost all pointers can be done.

 

However, the reference is clearer and safer than the code written by the pointer, and there is no invalid reference. You do not need to release the reference explicitly, so there will be no possible release error of the pointer.

 

You need to use a pointer to change the pointing position.

 

One way is to consider who owns the memory. If the code that receives the variable is responsible for releasing the memory associated with the object, the pointer of the object must be accepted. If the code that receives the variable does not need to release the memory, it should accept the variable reference. That is, unless you need to dynamically allocate memory or change or release the pointer value elsewhere, you should use references instead of pointers. (This rule also applies to independent variables, function or method parameters, functions, or method return values.

 

 

 

Keyword:

 

1. const keywords:

 

Specifies or requires that the declared variables remain unchanged.

 

Const has two different but related usage: one is an identifier variable and the other is an identifier method.

 

A. const variable: declares that this variable cannot be modified. Any variable can be identified as const, including global variables and class data members. You can also use const to specify the parameters of a function or method.

 

Const double PI = 3.14159; // equivalent to # define PI 3.14159

 

Const pointer:

 

Int x = 5;

 

Const int * p = & x; // The x value cannot be modified by the pointer p, but can be modified by x itself.

 

* P = 10; // error

 

X = 10; // OK

 

Int const * p = & x; // equivalent to const int * p = & x

 

For:

 

Int x = 5, y = 8;

 

Int * const p = & x; // you can use p to modify the value of x, but you cannot modify the object pointed to by p.

 

* P = 10; // OK

 

P = & y; // error

 

Since p itself cannot be modified, it must be initialized when p is declared.

 

For:

 

Const int * const p = & x; // neither the x value nor the object pointed to by p can be modified through the pointer p.

 

B. const reference:

 

The const keyword used for reference is generally simpler than the const keyword used for pointer. There are two reasons: 1. the reference is const by default, that is, the variables they indicate cannot be modified (that is, other variables cannot be indicated ). Therefore, C ++ does not allow explicit use of const to identify referenced variables (for example, int & const xRef = x ). 2. Reference is generally only an indirect layer. You cannot create a reference to a reference. To obtain multiple indirect layers (indirect references), the only way is to create a pointer reference.

 

Therefore, the const reference we mentioned actually refers:

 

Int z;

 

Const int & zRef = z; equivalent to int const & zRef = z;

 

ZRef = 4; // error

 

Z = 4; // OK

 

Const reference is the most common parameter used as a function or method.

 

Note: when an object is passed as a parameter, the default method should be to pass the const reference. The const should be removed only when the passed object needs to be changed.

 

C. const Method

 

The data member of the class cannot be modified when the method is declared.

 

 

 

 

 

2. Keyword static

 

There are three static keywords in C ++, which seem unrelated to usage.

 

A. static data members and Methods

 

They do not belong to an object, but belong to this class.

 

B. static connection

 

C ++ each source file is compiled independently, and the obtained object files must be connected together. Each name in the C ++ source file, including the function and global variables, has a connection, which may be an internal connection or an external connection. External connection means that this name is available for other source files. An internal connection (also known as static linkage) means that this name is unavailable for other source files. By default, both functions and global variables have external connections. However, you can add the keyword static before the declaration to specify the internal (static) connection.

 

// FirstFile. cpp

 

Void f ();

 

Int main ()

 

{

 

F ();

 

Return 0;

 

}

 

The prototype of f () is given, but it is not defined

 

// AntherFile. cpp

 

# Include <iostream>

 

Using namespace std;

 

Void f ();

 

Void f ()

 

{

 

Cout <"f \ n" <endl;

 

}

 

The prototype and definition of f () are given.

 

It should be noted that it is legal to compile the prototype of the same function in two different files. If each source file uses # include to contain a header file, and the prototype of the method is placed in this header file, preprocessing is exactly the same job, its function is to have a prototype of the same method in different source files. The reason for using the header file is that it is easier to maintain a copy of the prototype (and keep it updated synchronously. However, the header file is not used for this example.

 

All these files can be compiled and connected. Because f () has an external connection, the main () function can call it from different files.

 

However, if the static keyword is used for method f () in the AntherFile. cpp file:

 

// AntherFile. cpp

 

# Include <iostream>

 

Using namespace std;

 

Static void f ();

 

Void f ()

 

{

 

Cout <"f \ n ";

 

}

 

Now, although there is no problem in compiling each source file, the connection will not succeed, because method f () uses an internal link, so that the method cannot be used in the source file FirstFile. cpp. The static method is defined, but it is not used in the source file. Some compilers will issue a warning.

 

Note that the static keyword is not required before the definition of f.

 

To achieve the internal (static) connection appeal effect, another method is to use an anonymous namespace. That is, wrap variables and functions in an unnamed namespace, instead of using the static keyword.

 

// AntherFile. cpp

 

# Include <iostream>

 

Using namespace std;

 

 

 

Namespace {

 

Void f ();

 

 

 

Void f ()

 

{Cout <"f \ n ";}

 

}

 

After the entities in the anonymous namespace are declared, these entities can be accessed anywhere in the same source file, but they cannot be accessed in other source files.

 

C. static variables in the function

 

This method creates a local variable and maintains the value of the variable only between the entry and exit scope. Static variables in a function are the same as global variables that can only be accessed from the function. A common usage of static variables is to "remember" whether a function has been initialized.

 

Void merge mtask ()

 

{

 

Static bool inited = false;

 

If (! Inited)

 

{Cout <"initing \ n"; inited = true ;}

 

}

 

However, static variables are often confusing and there is usually a better way to build code to avoid using static variables. In this case, you may want to write some constructors to complete the initialization work.

 

Avoid using independent static variables. The variable status should be maintained within the object.

 

 

 

3. Keyword extern

 

It seems to be opposite to static, and extern is used to declare external links. For example, const and typedef have internal links by default, so you can use extern to specify external links for them.

 

When a name is specified as extern, the compiler treats it as a declaration without defining it. This means that the compiler will not allocate space for it. You must provide additional definitions for variables without the keyword "extern.

 

// AntherFile. cpp

 

Extern int x;

 

Int x = 3; // equivalent to extern int x = 3;

 

The above file does not need to use extern, because x has an external link by default.

 

Use

 

// FirstFile. cpp

 

# Include <iostream>

 

Using namespace std;

 

 

 

Extern int x;

 

Int main ()

 

{Cout <"x =" <x <endl; return 0 ;}

 

If this file does not use extern, the connection will fail because there are two x variables in the global scope.

 

However, we recommend that you do not use full-play variables as much as possible. Global variables are confusing and prone to errors, especially in large programs. To complete such functions, you should use static class members and methods.

 

 

 

4. initialization sequence of non-local variables

 

Global variables and static data members in the program are initialized before the main () function starts running. Given source files are initialized in the order they appear in the file.

 

However, C ++ is not specified and the initialization sequence of non-local variables in different source files cannot be guaranteed.

 

 

 

Forced conversion of types and types:

 

Typedef

 

Provides a new name for an existing type. There is no new type-only a new method to reference the original type is provided.

 

The most common usage is to provide a manageable name for the actual type name.

 

Type forced conversion:

 

Use () in C for forced conversion. C ++ provides four new types of forced conversion methods: static_cast, dynamic_cast, const_cast, and reinterpret_cast. The C ++ type should be forcibly converted. Because the forced conversion of C ++-style types will complete more type checks.

 

Const_cast: constants of variables can be removed. This is the only type forced conversion that allows constant removal of variables among the four types. Theoretically, the mandatory conversion of the const type is not required. If the variable is declared as const, it should remain unchanged. But sometimes this is the case: the function specifies a const variable, but then the const variable must be passed to a function that obtains non-const variables. The correct approach is to maintain const consistency in the program, but this is not always the case, especially when using a third-party library. Therefore, this type is sometimes required for forced conversion.

 

Void g (char * str)

 

{}

 

Void f (const char * str)

 

{G (const_cast <char *> (str ));}

 

 

 

Static_cast:

 

You can use static_cast to display the conversions directly supported by C ++.

 

Int I = 3;

 

Double result = static_cast <double> (I );

 

You can also use static_cast to display the conversions allowed by user-defined constructors or conversion routines.

 

For example, Class A has A constructor. This constructor takes an object of Class B, so you can use static_cast to convert object B to object. However, in most cases, the compiler automatically completes the conversion.

 

Another method is to perform forced downward type conversion in the inheritance hierarchy.

 

Class Base

 

{

 

Public:

 

Base (){}

 

Virtual ~ Base (){}

 

};

 

Class Derived: public Base

 

{

 

Public:

 

Derived (){}

 

Virtual ~ Derived (){}

 

};

 

Int main ()

 

{

 

Base * B;

 

Derived * d = new Derived ();

 

B = d; // It is automatically converted up.

 

D = static_cast <Derived *> (B); // static_cast is required.

 

 

Base base;

 

Derived derived;

 

Base & br = base;

 

Derived & dr = static_cast <Derived &> (br );

 

Return 0;

 

}

 

This type of forced conversion can be applied to pointers and references, but cannot process the object itself. The static_cast conversion does not complete the runtime type check.

 

Static_cast cannot directly convert one type of pointer to another unrelated type. You cannot use static_cast to convert a pointer to an int. You cannot use static_cast to directly convert one type of object to another type of object. You cannot use static_cast to forcibly convert a const type to a non-const type. Static_cast cannot perform any meaningless conversions.

 

 

 

Reinterpret_cast: it is more powerful than static_cast, but has lower security.

 

You can forcibly convert one type of pointer to another type, even if they are unrelated to the inherited structure. Similarly, you can forcibly convert a type of reference to another type of reference, even if the two types of reference are irrelevant. You can also convert a pointer to an int or an int to a pointer. Be careful when using reinterpret_cast, because it will interpret the original bit as different types without any type check.

 

 

 

Dynamic_cast: When dynamic_cast is used for type forced conversion, the type is forcibly converted in the inheritance hierarchy to complete the type check. You can use dynamic_cast to forcibly convert pointers or references. Dynamic_cast checks the runtime type information of the underlying object at runtime. If forced type conversion is meaningless, dynamic_cast returns NULL (for pointer conversion), or throws a bad_cast exception (for reference conversion ).

 

Class Base

 

{

 

Public:

 

Base (){}

 

Virtual ~ Base (){}

 

};

 

Class Derived: public Base

 

{

 

Public:

 

Derived (){}

 

Virtual ~ Derived (){}

 

};

 

Int main ()

 

{

 

Base * B;

 

Derived * d = new Derived ();

 

B = d; // It is automatically converted up.

 

D = dynamic_cast <Derived *> (B); // dynamic_cast is required.

 

 

Base base;

 

Derived derived;

 

Base & br = base;

 

Try {

 

Derived & dr = dynamic_cast <Derived &> (br );

 

} Catch (bad_cast &) {cout <"bad_cast !" <Endl ;}

 

Return 0;

 

}

 

 

 

Scope parsing OPERATOR:

 

First, check the name to be accessed in the innermost layer, and then gradually outward until the global scope. No namespace, function, or class names are in the global scope.

 

Sometimes, names in some scopes hide the same names in other scopes.

 

In addition, you do not want to access the name of the default scope in this scope, but want to access the same name in other scopes, you need to use the scope resolution OPERATOR:, to limit a scope for each name.

 

Note: The global scope is not named, so if you want to access the name in the global scope, use: directly without adding the scope name.

 

 

 

Header file: Avoid loop reference and multiple inclusion of the same file in the header file. The # ifndef mechanism can be used to avoid loop inclusion and multi-inclusion.

 

 

 

// Logger. h

 

# Ifndef _ LOGGER __

 

# Define _ LOGGER __

 

# Include "Preferences. h"

 

Class Logger {};

 

# Endif/_ LOGGER __

 

To avoid header file problems, another method is to reference them in advance.

 

 

 

Tools used in C

 

1. variable-length function parameter list such as print ()

 

Void debugOut (char * str ,...);

 

... Indicates any number and type of parameters. To access these parameters, you must use the macro defined in <cstdarg>. You can declare a variable of the va_list type and call va_start () to initialize the variable. The second parameter of va_stat () must be the rightmost name variable in the parameter list. All functions require at least one name parameter. After this parameter is completed, it calls va_end () to end access to the variable length parameter list. After calling va_start (), you must call va_end () to ensure that the function call stack remains consistent at the end.

 

Try not to use this method: because you do not know the number of parameters and the parameter type.

 

2. Preprocessing macros

 

# Define SQUARE (x) * (x) // note that the pre-processing macro must be enclosed in parentheses.

 

As experience, try not to replace inline with macros. Errors are easy. If you do not check the type, debugging errors may occur (because the code you write is not the code that the compiler sees ).

 



From my dream pursued by me

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.