C ++ flexible and error-prone features-02 and error-02

Source: Internet
Author: User
Tags variadic

C ++ flexible and error-prone features-02 and error-02
C ++ notes series: flexible and error-prone features-02

Keywords:

  • Type and type conversion
  • Typedef
  • Scope
  • Header file
  • C-style tools
Type and type conversion typedef

typedefProvide a new name for the existing type declaration. You can settypedefFor existing type declarationsSynonym.

typedef int* IntPtr

The new type name and its alias can be used interchangeably:

int* p1;IntPtr p2;

Fundamentally, they are of the same type:

// Completely valid p1 = p2; p2 = p2;

typedefThe most common usage is to provide a name that is easy to manage when the type declaration is too clumsy. Especially in the template.

If you don't want to bother writingstd::vector<std::string>, You can usetypedef,

typedef std::vector<std::string> StringVector;void ProcessVector(const StringVector& vec) {}int main {StringVector my_vector;return 0;}

In fact, STL is widely used.typedefFor examplestringIs defined as follows:

typedef basic_string<char, char_traits<char>, allocator<char>> string

Function pointer typedef

Function pointers in C ++ are not common (virtualKeyword substitution), but in some cases, you still need to obtain the function pointer. However, when defining function pointers,typedefIt is the most confusing.

Consider a dynamic link library (DLL) with the nameMyFunc(). OnlyMyFunc()To load the database.

Assume thatMyFunc()The prototype is as follows,

int __stdcall MyFunc(bool b, int n, const char* p);

__stdcallThe Microsoft-specific command indicates how to pass parameters to functions and clean up.

Now you can usetypedefDefine an abbreviated name (MyFuncProc) for the pointer to the function, which has the prototype shown above:

typedef int (__stdcall *MyFuncProc)(bool b, int n, const char* p);

Note:typedefNameMyFuncProcIt is quite confusing to embed it in this syntax. Another more concise method to solve this problem is described in the next section.Type alias.

Type alias

In some cases, the type alias RatiotypedefIt is easier to understand.

typedef int MyInt;

You can use a type alias for writing.

using MyInt = int;

WhentypedefType aliases are especially useful when they become complex.

Typedef int (* FuncType) (char, double); // use the type alias using FuncType = int (*) (char, double );

Type aliasNot just easy to readtypedef, Used in the templatetypedef,typedefThe problem becomes very prominent.

For example, the following class template is available:

Template <typename T1, typename T2> class MyTemplateClass {}; // oktypedef MyTemplateClass <int, double> OtherName; // Errortypedef MyTemplateClass <T1, double> OtherName; // to do this, use the template alias template <typename T1> using OtherName = MyTemplateClass <T1, double>;
Type conversion

C ++ provides four types of conversions:static_cast,dynamic_cast,const_cast,reinterpret_cast. We strongly recommend that you use only C ++-style type conversion in the new code, which is safer and more syntactic than C-style()Better.

1. const_cast

const_castIt is the most direct and can be used for constant features of variables. This is unique among the four types of conversions.Discard constant featuresType conversion. Of course, theoretically, it is not necessaryconstType conversion. Variable isconst, It should always beconst.

However,Sometimes a function needsconstVariable passed to non-constVariable Function.The best way is to maintainconstConsistency. In most cases, a third-party library is used. There is no way to construct a new program.

// Third-party external method extern void ThirdPartyLibraryMethod (char * str); void f (const char * str) {ThirdPartyLibraryMethod (const_cast <char *> (str ));}
2. static_cast

Displays the conversions directly supported by C ++. For example, in an arithmetic expressionintConvertdoubleTo avoid truncation, you can usestatic_cast.

Int I = 3; int j = 4; // you only need to convert one of them to ensure that the floating point Division double result = static_cast <double> (I)/j;

You can also usestatic_castExecute the explicit conversion. For example, the constructor of Class A can use the object of Class B as A parameter.static_castConverts object B to object. This type of behavior is often required. Generally, the compiler automatically and implicitly executes this conversion.

static_castAnother usage is to execute downward conversion in the class inheritance hierarchy.Note: it can only be used for pointer and reference of an object, and cannot be used to convert the object itself.

Note that,static_castDo not perform type detection during running. For example, the following code may cause disastrous consequences, including memory rewriting exceeding the boundaries of objects.

// Derived inherits from BaseBase * B = new Base (); Derived * d = static_cast <Derived *> (B );

You can usedynamic_cast.

static_castIt is not omnipotent.constType conversion to non-const type,A pointer of a certain type cannot be converted to another unrelated type.Cannot directly convert the object type. Basically, the type rule cannot be converted meaningless.

3. reinterpret_cast

reinterpret_castRatiostatic_castMore powerful and less secure. Can be usedThe execution is technically not allowed by rules, but in some cases type conversion is required.For example, two references can be converted to one another, even if the two are irrelevant. Similarly, even if the two pointers do not have an inheritance relationship, you can convert a pointer type to another pointer type.

reinterpret_castIt is often used to convert a pointervoid*Andvoid*Convert to pointer.

Class X {}; class Y {}; int main () {X x; Y y Y; X * px = & x; y * py = & Y; // The conversion between unrelated pointer types can only be performed using reinterpret_castpx = reinterpret_cast <X *> (py); void * p = px; px = reinterpret_cast <X *> (p ); X & rx = x; Y & ry = reinterpret_cast <Y &> (x );}

Theoretically,reinterpret_castYou can also convert the pointerint, OrintConvert to pointer. However, such programs may be incorrect. On many platforms (especially 64-bit), pointers andint. For example, on a 64-bit platform, the pointer is 64-bit, And the integer may be 32-bit. Converting a 64-bit pointer to a 32-bit integer will result in the loss of 32-bit.

In additionreinterpret_castYesBe especially careful that it will not perform any type detection.

4. dynamic_cast

dynamic_castProvides runtime detection for type conversions within the inheritance hierarchy. It can be used to convert pointer or reference.dynamic_castCheck the type information of the underlying object at runtime. If the type conversion is meaningless,dynamic_castReturns a null pointer (for pointers) or throwsstd::bad_castException (for reference ).

Note that the running type information is stored in the virtual table of the object. Therefore, to usedynamic_cast,The class must have at least one virtual method.. If the class does not have a virtual table, usedynamic_castCompilation errors may occur.

The followingdynamic_castWill throw an exception:

# Include <iostream> using std: bad_cast; using std: cout; class Base {public: Base () {} virtual ~ Base () {}}; class Derived: public Base {public: Derived () {} virtual ~ Derived () {}}; int main () {Base base; Derived derived; // change it to Base & br = derived; no exception is thrown. Base & br = base; try {Derived & dr = dynamic_cast <Derived &> (br);} catch (const bad_cast &) {cout <"Bad cast! \ N ";}}
5. Summary of type conversion
Situation Type conversion
Delete the const feature Const_cast
Type conversion supported by the language (for example, int is converted to double, int is converted to bool) Static_cast
Type conversion supported by user-defined constructors or conversion routines Static_cast
Class Object to other (irrelevant) Class Object Unable to complete
The pointer (pointer-to-object) of the Class object is converted to the pointer of other class objects in the same inheritance hierarchy. Static_cast or dynamic_cast (recommended)
Convert a reference-to-object to a reference of another class object in the same inheritance hierarchy. Static_cast or dynamic_cast (recommended)
Type pointer conversion (pointer-to-type) is another unrelated type pointer Reinterpret_cast
Reference-to-type is a reference of another unrelated type. Reinterpret_cast
The function pointer (pointer-to-function) is another function pointer. Reinterpret_cast
Scope resolution

You can use the create scope

  • Namespace
  • Function Definition
  • Block defined by curly brackets
  • Class Definition

When trying to access a variable, function, or category, the name will be searched from the latest scope, and then adjacent scopes, and so on, until the global scope.

If you do not want to use the default scope to parse a name, you can use the scope resolution operator.::And the specific scope. For example, for a static method of a method class, the first method is to place the class name (method scope) and scope parsing operator before the method name. The second method is to access the static method through the class object.

Header file

Header files provide abstract interfaces for code. When using header files, you must note that you do not need to reference them cyclically or include the same header file multiple times. The most common method is to use#ifndefMechanism.

#ifndefIt can be used to avoid loop inclusion and multiple inclusion. At the beginning of each header file,#ifndefIndicates whether a tag is defined. If the tag has been defined, it indicates that the header file has been included.#endifThis command is generally at the end of the file. If the tag is not defined, the tag will be defined. Repeated inclusion will be ignored. This mechanism is also calledHeader file protection (include guards).

#ifndef LOGGER_H#define LOGGER_H#include "Preferences.h"class Logger {public:static void setPreferences(const Preferences& prefs);static void logError(const char* error);};#endif // LOGGER_H

If the compiler supports#pragma once(Visual C ++ or g ++), which can be written as follows:

#pragma once#include "Preferences.h"class Logger {public:static void setPreferences(const Preferences& prefs);static void logError(const char* error);};

Forward declarations is another tool to avoid header file problems. If you need to use a class but cannot contain its header file (for example, this class is heavily dependent on the currently written class), you can tell the compiler that such a class exists, but it cannot be used.#include. Of course, you cannot use this class in the Code. This named class exists only after the link is successful.

# Ifndef LOGGER_H # define LOGGER_Hclass Preference; // pre-declaration class Logger {public: static void setPreferences (const Preferences & prefs); static void logError (const char * error );};

In large projects, using a pre-declaration can reduce the compilation and re-Compilation Time, because it destroys the dependency of a header file on other header files. However, the pre-declaration also hides dependencies. When the header file is changed, your code will skip the necessary re-compilation process.

Pre-declaration may sometimes impede header file changes to APIs, especially functions, such as expanding the parameter type. In addition, general projects do not need to shorten the Compilation Time.

It is recommended that functions always use#include, Class template priority#include.

C Tool

C language has some obscure features that can be seen occasionally in C ++. For example, variable length argument lists and preprocessor macro (preprocessor macros ).

Variable Length Parameter List

In C language, this feature must be unique,printf()This feature is used.

Note that the new Code should passvariadicThe template uses a type-safe variable length parameter list.

#include <cstdio>#include <cstdarg>bool debug = false;void DebugOut(const char* str, ...) {va_list ap;if (debug) {va_start(ap, str);vfprintf(stderr, str, ap);va_end(ap);}}int main(int argc, char const *argv[]) {debug = true;DebugOut("int %d\n", 5);DebugOut("String %s and int %d\n", "hello", 5);DebugOut("Many ints: %d, %d, %d, %d, %d\n", 1, 2, 3, 4, 5);return 0;}

Callva_start()Must be called laterva_end()Make sure that the stack is stable after the function is completed.

1. Access Parameters

You can useva_arg(). However,If no explicit method is provided, the end of the parameter list cannot be known.

The first parameter can be used to calculate the number of parameters, or when the parameter is a set of pointers, the last parameter can be requirednullptr.

In the following example, the caller needs to specify the number of parameters provided in the first named function.

void PrintInts(int num, ...) {int temp;va_list ap;va_start(ap, num);for (int i = 0; i < num; ++i) {temp = va_arg(ap, int);cout << temp << " ";}va_end(ap);cout << endl;}
2. Why not use the C-style variable-length parameter list?
  • The number of parameters is unknown. For examplePrintInts()You must trust the caller to pass a parameter with the same number as the first parameter.
  • The parameter type is unknown.

Avoid using a variable-length parameter list in the C style as much as possible.array,vectorOr the initialization list introduced by C ++ 11 is better. You can also usevariadicThe template uses a type-safe variable length parameter list.

Preprocessing macro

Use inline functions instead of macros. Macro errors are not performed. When macro is called, the preprocessing phase will automatically expand and replace, but the function call semantics will not be used. This line may cause unpredictable consequences. Also, macros are prone to errors. For example, there is a problem with writing like this:

#define SQUARE(x) (x * x)

Assume thatSQUARE(2 + 3).2 + 3 * 2 + 3The calculation result is 11, not 25 of the expectation. The correct method is as follows:

#define SQUARE(x) ((x) * (x))

Note that the outermost parentheses cannot be omitted, otherwise they may be combined in arithmetic expressions due to priority issues.

If the calculation is complex, repeated expansion and replacement means that there will be a large overhead in repetitive operations.

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.