ebook img

C++ Programming Language: a QuickStudy Laminated Reference PDF

6 Pages·9.992 MB·
Save to my drive
Quick download
Download
Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.

Preview C++ Programming Language: a QuickStudy Laminated Reference

WORLD’S #1 QUICK REFERENCE SOFTWARE GUIDE Programming Language The code in this guide was tested against GCC 8.2.1 and should work with any C++ compiler that fully implements the C++17 standard. Source Code Comments Fundamental Types Storage Class Specifiers • There are two types of source code comments: • Alternate ways to specify a given type (e.g., signed short int) are not Used in declarations to indicate storage duration and – Line comments start with two forward slashes // listed. linkage properties and continue until the end of the line of text. • The int keyword may be omitted when modifiers (e.g., signed, unsigned, • static: Indicates the object is allocated when the – Block comments can contain multiple lines of short, and long) are specified. program starts and deallocated when the program text, start with /*, and end with */. • The C++ standard does not strictly specify the widths of the fundamental terminates. • Prior to compilation, comments are replaced with a types. The widths shown below are typical for modern systems. Some single space character. platforms may have different widths/ranges. – When used to declare a class member, it indicates Example: • Use the std::is_fundamental type trait to determine if a type is the member is a class member instead of a class std::cout << "Hello, world!\n"; // Say hello! fundamental. instance member. /* • Use std::numeric_limits to determine ranges. – When used in a declaration at namespace scope, This next line of code prints it indicates internal linkage. a hello world message to standard out. FUNDAMENTAL TYPES */ Width • extern: Indicates that the object being declared is std::cout << "Hello, world!\n"; Type (Bits) Range not being defined but only declared and that it is has bool 8 0,1 (false, true) external linkage. char 8 -128…127 – Objects declared as extern must be defined (once) The Preprocessor signed char 8 -128…127 in a separate definition with external linkage, or a • Preprocessor directives can be embedded in C++ unsigned char 8 0…255 source code. They comprise a text processing language short int 16 -32768…32767 linker error will occur. unsigned short • thread_local: Indicates that the object being (separate from the C++ language itself) used to modify 16 0…65535 int declared is allocated (for each thread) when the C++ source file text prior to compilation. • The preprocessor supports several categories of int 32 -2147483648…2147483647 thread is created and is deallocated when the thread unsigned int 32 0…4294967295 functionality: File inclusion, macro definition and is destroyed. Each thread has its own instance of the long int 64 -9223372036854775808…9223372036854775807 expansion, conditional source code inclusion, and unsigned long object. diagnostic messaging. int 64 0…18446744073709551615 • The following standard preprocessor directives long long int 64 -9223372036854775808…9223372036854775807 Objects are supported: #include, #define, #undef, #if, #ifdef, unsigned long #ifndef, #else, #elif, #endif, #line, #pragma, #error. long int 64 0…18446744073709551615 Instances of types – Additional nonstandard directives (e.g., #warning) float 32 -3.40282e+38…3.40282e+38 • Variable: A named object. may also be supported. double 64 -1.79769e+308…1.79769e+308 • Unnamed objects (temporary objects): Created • The C++ standard requires that the long double 128 -1.18973e+4932…1.18973e+4932 during implicit type conversion and when returning a preprocessor predefines the following macros: wchar_t 32 -2147483648…2147483647 __cplusplus, __DATE__, __FILE__, __LINE__, char16_t 16 0…65535 value from a function. __STDC_HOSTED__, __STDCPP_DEFAULT_ char32_t 32 0…4294967295 • When an object is created, a region of memory must void N/A N/A be reserved to store the object’s state information. The NEW_ALIGNMENT__, __TIME__. – The following macros may be defined, condi- std::nullptr_t 64 N/A amount of memory needed to store an object’s state is tionally, depending on implementation-specific known as the object’s size. details: __STDC__, __STDC_MB_MIGHT_ Enumerations – The size of an object or type can be determined NEQ_WC__, __STDC_VERSION__, __STDC_ using the sizeof operator. ISO_10646__, __STDCPP_STRICT_POINTER_ A type whose values are restricted to a set of named constants. The • An object of a type having at least one virtual SAFETY__, __STDCPP_THREADS__. named constants themselves are of an integral type referred to as the function is known as a polymorphic object. underlying type. – Polymorphic objects should almost always have Line Continuation #include <iostream> virtual destructors. When a backslash character \ is immediately followed // unscoped enum (deprecated) • Objects have alignment requirements that impose by a newline character, both characters are deleted enum Color : char { Red, Green, Blue }; restrictions on an object’s memory address. before compilation. This effectively allows the current // scoped enum line to be continued on the next line by ending the enum class Role : char { Mom=1, Dad=3, Son, Daughter }; Object Lifetime current line with a backslash. • Significant events in an object’s life cycle: int main() { – Reservation of storage (memory) for the object Role role{Role::Son}; Keywords – Initialization/construction (may be a trivial con- std::cout << "role type = [" << typeid(Role).name() << "]\n"; structor that performs no action) alignas continue friend register* true alignof decltype goto rperientt_ecra-st try ssttdd::::ccoouut t< << <" r"orloe lvea lsuiez e= [=" [<"< <s<ta tsiicz_ecoafst(<rionlte>)( r<ol<e )" ]<\<n ""];\n"; –– ODbesjetrcut citnio lniv (em/naoyr mbea la s ttraitveial destructor that asm default if return typedef return 0; performs no action) auto delete inline short typeid } – Release of storage bool do int signed typename Output: • During construction and destruction, member break double long sizeof union case dynamic_cast mutable static unsigned role type = [4Role] functions including virtual member functions may catch else namespace static_assert using role size = [1] be called. char enum new static_cast virtual role value = [4] – When a virtual function is called during these char16_t explicit noexcept struct void times, it is always called on the object being cchlaasrs32_t eexxpteorrnt nouplelrpattror stewmitpclhate vwoclhaatirl_et Incomplete Types constructed or destructed. Care must be taken when const false private this while Types for which objects cannot be declared, since the compiler cannot calling member functions from within constructors constexpr float protected thread_local determine the size of the object. Void, forward declarations of structs, and destructors, since the object may be in a state const_cast for public throw classes, unions, arrays of unknown size, and arrays whose elements are that violates class invariants, which could lead to *Unused, but reserved for possible future use of an incomplete type are incomplete types. undefined behavior. Attributes Object Initialization – Parenthesized expression-list, in which the expression-list is interpreted as argu- Attributes (attribute-specifier-seqopt) can be used to specify information about types,   The act of assigning an initial state to an ments to a constructor variables, names, blocks, and translation units. Various tools in the toolchain may object during creation EX: std::complex<double> point(1,0); implement their own implementation-specific attributes. However, the standard does define • Generally, all objects should be initialized, – Assignment expression the following standard attributes: noreturn, carries_dependency, deprecated, fallthrough, either implicitly (via a default constructor) EX: std::complex<double> point = 1; nodiscard, maybe_unused. or explicitly. Objects can be explicitly – Initialization list Examples: EX: std::complex<double> point = {1,0}; [[ noreturn ]] void onError() { throw std::runtime_error(“Error.”); } initialized in three ways: [[ maybe_unused, deprecated ]] void oldImplementation(); 1 New Features (continued) Compound Types string " "foo" ESCAPE SEQUENCES raw string R" R"(\n)" Defined in terms of other types. Arrays, functions, pointers to objects or UTF-8 string u8" u8"foo", u8R"foo\n" Name Esc. Seq. functions, pointers to nonstatic class data or function members, references, string UTF-16 string u" u"foo", uR"foo\n" new line \n classes, unions, and enumerations are compound types. Use the std::is_ UTF-32 string U" U"foo", UR"foo\n" horizontal tab \t compound trait type to determine if a type is a compound type. wchar_t string L" L"foo", LR"foo\n" #include <string> vertical tab \v • The octal (0) and hex (0x) prefixes • Character and string literals may backspace \b int main(int argc, char **argv) { can be used with any literal integer contain escape sequences that are int intArray[10]; // array of 10 integers suffix. used to represent commonly used carriage return \r iinntt ** *p IpnptI n=t n=u lnlupltlrp;t r/;/ /p/o ipnotienrt etro taon ai nptoeignetrer to an integer • The raw string prefix (R) can nonprintable characters. form feed \f // function pointer that takes a double and returns an integer be used with any string literal alert/beep \a int (*fp)(double) = nullptr; prefix to disable escape sequence backslash \\ // pointer to char that points to an array of 6 characters processing. // containing the null-terminated string “Scott” single quote \' c/h/a ru ncioonnst * name = “Scott”; Ulitseerra-ldse tfion perdo dliutecrea lv asulufefisx eosf aursee rs-udpepfionretded t,y wpehsi.ch allow double quote \" union String Example of a user-defined literal: any char value (octal) \000 { std::string str; #include <iostream> any char value (hex) \xhhh std::wstring wstr; using meters = double; }; constexpr meters operator"" _feet (long double n) { return 0; return 0.3048 * n; } } constexpr meters operator"" _inches (long double n) { Output: Type Aliases return 0.0254 * n; } 100 feet = [30.48] meters. Type aliases are declared using the following syntax: 100 inches = [2.54] meters. int main() { using identifier attribute-specifier-seqopt= type-id; std::cout << "100 feet = [" << 100.0_feet << "] meters.\n"; Example: std::cout << "100 inches = [" << 100.0_inches << "] meters.\n"; using Age = unsigned char; using FirstName = std::string; return 0; } using Date = struct { unsigned char day; unsigned char month; Classes member of a union is undefined behavior. unsigned int year; – Unions have the following limitations: }; User-defined types that represent concepts » A union may not have virtual functions. Alias template declarations are declared using the following syntax: • Classes encapsulate state and behavior, which are » A union may not have a base class. template <template-parameter-list> using identifier attribute-specifier-seqopt = defined by the member data and member functions. » A union may not be used as a base class. tEyxpaem-idp;le: • External accessibility of member data and functions » A union may not contain a nonstatic data template <typename T> using MyVector = std::vector<T, MyAllocator<T>>; can be controlled via access specifiers (private, member of reference type. protected, and public). » If any nonstatic data members of a union have CV Qualifiers objects declared as const cannot be • User-defined classes can be made to behave just nontrivial special member functions, the corre- modified except by using const_ like the built-in fundamental types due to the sponding member function of the union must be CV (const and volatile) type qualifiers cast or mutable. operator overloading capabilities provided in C++. user-provided or it will be deleted for the union. are used in declarations to indicate • volatile: Objects or subobjects of There are three different kinds of classes: – A union is declared as: if objects of the declared type objects declared as volatile may • Class-key: Specifies which kind of class is being union { member-specification }; can be modified or if they may be have their value changed outside declared. » This is called an anonymous union. modified outside the current thread of the current thread of execution • Struct: Similar to a class, except the default access Anonymous unions have additional execution. (prevents the compiler from specifier is public instead of private. limitations: • const: Objects or subobjects of performing certain optimizations). • Union: A class in which all of the nonstatic data ♦ All members must be public (private members occupy the same memory location, and and protected access specifiers are not therefore only one member of a union can be active/ allowed). Expressions identity; can be moved from – lvalue (can appear on the left of valid at any given time. The active/valid member ♦ If declared in a named namespace or global A sequence of operators and operands an assignment operator): Has of a union is the member most recently assigned a namespace, the union must be declared to that specify a computation identity; cannot be moved from value. Accessing the value of an inactive/invalid have static storage class. • The evaluation of an expression may – glvalue (generalized lvalue): cause side effects and may result in a Has identity; general category that Access Specifiers – When used in the base-specifier of a derived value (e.g., the result of the expression applies to xvalue and lvalue class, the access specifier indicates the acces- 1+1 is the value 2). – rvalue (can appear on the right Public, protected, and private access specifiers are used sibility the derived class has to the members of • Expressions have a type and of an assignment operator): to limit or grant access to member data and functions. the base class. a value category. The C++ Can be moved from; general • This is done is two ways: • The default access level for members of a type standard defined the following category that applies to prvalue – When used in the member-specification of a declared as a class is private. value categories: and xvalue; address may not class, struct, or union, the access specifier indi- • The default access level for members of a type – prvalue (pure rvalue): Does not be taken; can’t be assigned to; cates the accessibility of members that follow in declared as a struct or union is public. the class declaration. have identity; can be moved from can be used to initialize a const – xvalue (expiring value): Has lvalue reference Statements Literals An ordered sequence of one or more instructions that the program may execute • C++ supports expression statements, null statements, compound statements (blocks), selection statements, Constant values embedded into the source code iteration statements (loops), jump statements, declaration statements, and try-block statements. • Literal prefixes and suffixes are used to indicate the type of literal value. • Statements may be given labels for use with goto and switch statements. – The type of integer literals is assumed to be int if no suffix is specified. Expression Statements – The type of floating-point literals is assumed to be double if no suffix is specified. attribute-specifier-seqopt expression; EX: Assignment statements and function calls LITERAL PREFIXES & SUFFIXES Null Statements Category Type Prefix Suffix Example ; bool bool true, false Can be thought of as an expression statement in which no expression is specified. Used to provide an empty init- statement for a for loop or as a statement to associate a label with at the end of a compound statement. char ' 'a' char16_t u' u'a' Compound Statements (Blocks) character char32_t U' U'a' attribute-specifier-seqopt { statement-seqopt } wchar_t L' L'a' A sequence of statements enclosed by paired braces. Variables defined inside a compound statement are int 42 destroyed at the end of the block. int (octal) 052 Selection Statements int (hex) 0x2a unsigned 0 42U, 42u, 0x21u attribute-specifier-seqopt if constexpropt (init-statementopt condition) statement integer long 0X, 0x L, l 42L, 42l, 0x21L attribute-specifier-seqopt if constexpropt (init-statementopt condition) statement else statement long long U, u LL, ll 42LL, 42ll, 0x21LL attribute-specifier-seqopt switch (init-statementopt condition) statement unsigned long UL, ul 42UL, 42ul, 0x21UL Iteration Statements (Loops) unsigned long long ULL, ull 42ULL, 42ull, 0x21ULL attribute-specifier-seqopt for (for-range-decl : for-range-init ) statement floating- float F, f 42.0F, 42.f, 1.0e10f attribute-specifier-seqopt for (init-statementopt conditionopt ; expressionopt ) statement point double 42.0, 42., 1.0e10 attribute-specifier-seqopt while constexpropt (init-statementopt conditionopt ; expressionopt ) statement long double L, l 42.0L, 42.l, 1.0e10L attribute-specifier-seqopt do statement while ( expression ); 2 Jump Statements Operators Namespaces break; creotnutrinnu eex;pression; Pderneccee- Ativssitoycia- ODepsecrraiptotrio n Operator Alias Nduapmliecda tbiolonc/ckosl ltihsaiot np rienv leanrtg aec pcriodjeencttasl name return initializer-list; Group Note: Multiple namespace blocks that have goto identifier; 1 N/A Scope resolution :: the same name are allowed. Array subscript [ ] <: :> Declaration Statements simple-declaration: FMuenmctbioern sceallelction (. o)r -> Name Hiding attribute-specifier-seqopt decl-specifier-seq init-declarator-listopt; Postfix decrement -- Since the name lookup process stops looking decl-specifier-seq: Postfix increment ++ for candidates once a nonempty set of decl-specifier attribute-specifier-seq Constant type const_cast opt candidates is found in a particular scope, decl-sdpeeccli-fisepre:cifier decl-specifier-seq 2 Lriegfhtt to D cyonnavmerisci otynpe dynamic_cast names can be hidden by declarations in storage-class-specifier conversion nested scopes. This can result in unexpected defining-type-specifier Reinterpret type reinterpret_cast behavior and misunderstanding, so it is best function-specifier conversion avoided, if possible. Static type static_cast friend conversion typedef Type name typeid Polymorphism constexpr inline Address-of & A feature of a computer language that Cast ( ) init-declarator-list: Create object new allows a single interface to be used to init-declarator Destroy object delete access functionality having multiple init-declarator-list, init-declarator Indirection * implementations, where the specific dineict-ladredacetlcoalrra:artaotro:r initializeropt 3 Rleifgtht to LOPronegefii’cxs a cdlo enmcorptemlemenetnt !~-- ncoomtpl iomr ptylepmese bnetaintigo na citnevdo okned is based on the type ptr-declarator Prefix increment ++ • C++ supports the three kinds of noptr-declarator parameters-and-qualifier trailing-return-type Unary negation - polymorphism: Ad hoc polymorphism, ptr-declarator: Unary plus + parametric polymorphism, and subtype noptr-declarator Size of an sizeof polymorphism. ptr-operator ptr-declarator object or type – Ad hoc polymorphism: Supported noptr-declarator: 4 Left to Pointer-to-member .* or ->* via function and operator overloading; declarator-id attribute-specifier-seqopt right an example of static polymorphism noptr-declarator parameters-and-qualifiers Left to Division / (compile-time polymorphism). noptr-declarator [ constant-expression ] attribute-specifier-seq 5 Modulus % opt opt right – Parametric polymorphism: Supported ( ptr-declarator ) Multiplication * via templates; an example of static poly- parameters-and-qualifiers: Left to Addition + trailin(g p-arertaurmrenef--tqteyurp-adele:ificelarorpat ntiooenx-ccelaput-ssep )e ccivfi-eqruopat laifitterrib-suetqeo-pstpecifier-seqopt 67 rLriigegfhhttt to SLRueigfbtht rsta hscihtfiitoftn -<><> – mSviuoab riptnyhtpeisremf ap c(oeclsoy mm(apboisrletpr-ahticimst mcel :pa soSsluyepsm)p ooarnrptdeh dis m). -> type-id derived concrete classes; an example Greater than > ptr-operator: Greater than >= of dynamic polymorphism (run-time * attribute-specifier-seqopt cv-qualifier-seqopt Left to or equal to polymorphism). & attribute-specifier-seqopt 8 right Less than < && att-seqopt Less than <= nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt or equal to Name Resolution & Scopes cv-qucavli-fiqeura-sliefiqe:r cv-qualifier-seqopt 9 Lriegfhtt to EInqeuqaulaitlyity =!== not_eq • Amsu sat pdreotgerrmamin ies tchoem dpeiclleadr,a ttihoen c aosmsopciilaetre d cv-qualifier: cvoonlasttile 10 Lriegfhtt to Bitwise AND & bitand wcliatshs enaacmh ev,a arniadb nlea mnaemspea, cfeu nncatmioen int ame, ref-qualifier: 11 Left to Bitwise ^ xor encounters. This process is known as name right exclusive OR & resolution. && 12 Left to Bitwise | bitor • Since C++ allows multiple functions to right inclusive OR declarator-id: have the same name in the same scope, ...opt id-expression 13 Lriegfhtt to Logical AND && and name resolution of functions and function Try-Block Statements templates may take two steps: name Left to try-block: 14 right Logical OR || or lookup (which may result in multiple attribute-specifier-seq try compound-statement handler-seq candidates being found) followed by opt Right to function-try-block: 15 left Conditional ?: overload resolution. try ctor-initializeropt compound-statement handler-seq Addition += – Overload resolution: Process by which handler-seq: assignment the compiler determines which one of handler handler-seqopt Assignment = multiple candidate functions is the best handler: Division /= match, based on the number and types of catch ( exception-declaration ) compound-statement assignment the function parameters. After the com- exception-declaration: Bitwise ADD &= and_eq piler selects the best candidate, implicit aa..tt.ttrriibbuuttee--ssppeecciififieerr--sseeqqoopptt ttyyppee--ssppeecciififieerr--sseeqq daebcsltararactt-odreclaratoropt B aOistRwsi igasnsesm eigxenncmltuesinvte ^= xor_eq ttyop ceo cnovnevrte arsrgiounm menatys tthoe tnh eb ety epmesp ltohyaet d Labeled Statements Right to Bitwise inclusive |= or_eq the selected function requires. 16 OR assignment – Name resolution of variable names, attribute-specifier-seqopt identifier : statement left Left-sift <<= class names, and namespace names only attribute-specifier-seqopt case constant-expression : statement assignment requires a name lookup, which must attribute-specifier-seqopt default : statement M aossdiuglnums e nt >>= result in a single candidate being found. Multiplication *= • There are two kinds of name lookups: Functions assignment – Qualified: Performed when a name ap- Right-shift >>= pears on the right-hand side of the scope Named blocks of code that can be called assignment resolution operator :: . • Function parameters can be passed to the function as inputs. Subtraction -= » In these cases, the identifier on the left assignment Functions may return void (nothing), or some other object, of the scope resolution operator can Right to according to the declaration. 17 Throw expression throw be a class name, struct name, enum left • All function parameters (including references and pointers) are name, or namespace name. If there is Left to passed by value. 18 right Comma , no identifier to the left of the scope Basic function declaration syntax: resolution operator, it indicates that the name is in the global namespace. return-type function-name ( parameter-list ) { function-body } Explicitly specifying that the name is Example: int add(int a, int b) in the global namespace is required to { • The main function can be defined in one of two ways: refer to names in the global namespace return a + b; – int main() { function-body } that are hidden by another declaration. } – int main(int argc, char *argv[]) { function-body } – Unqualified: Performed when a name Main Function Example: appears without a preceding scope #include <iostream> resolution operator. In these cases, the • All C++ programs must contain a function named main, which compiler will try to resolve the name by is the function at which the program starts executing user-defined int main(int argc, char **argv) { searching the following scopes, stopping code. srtedt:u:rcno u0t; << “Hello, world!” << std::endl; when it finds the first match: • The main function is called just after nonlocal objects with static } » Block scope: Declarations in a com- storage duration are initialized. pound statement 3 » Local scope (a kind of block scope): Declarations in a function or Copy/Move Elision – When returning an object from a function lambda body • Under certain circumstances, the compiler » This is known as return value » Statement scope: Declarations in if, for, while, and switch statements can automatically remove unnecessary object optimization. » Function parameter scope copy/move operations in order to make the – When a temporary object is passed to a » Function scope: Labels are at function scope and are valid anywhere resulting code more efficient. This removal – fWunhcetnio tnh rboyw vinaglu aen exception object by inside the function, not just following declarations is called copy/move elision. A copy/move value » Namespace scope: Declarations made inside the current namespace elision is usually performed in the following – When catching an exception object by » Class scope: Declarations made inside the current class declaration situations: value » Enumeration scope: Declarations made inside the current scoped enum declaration » Template parameter scope Special Member Functions » Global scope: Global declarations outside any class, function, or There are six special member functions that the compiler can declare and define automatically, in namespace (file scope) some cases. Special member functions should not be explicitly defined, unless necessary. • Unqualified function names (including overloaded operators) can be looked up using argument-dependent lookup (Koenig lookup). Special Conditions Required for Default – This allows unqualified functions to be used to call functions in a Member Form for Class T the Compiler to Implicitly Implementation namespace, as long as one or more of the function argument types are in Function Define the same namespace. Example of argument-dependent lookup: Default T::T(); Does nothing No explicitly declared #include <iostream> constructor constructors namespace exmpl { Copy Copies all No explicitly declared move class MyClass {}; constructor T::T(const T&); members constructor or move void myFunc( MyClass const & ) {}; assignment } No explicitly declared move int main() { Copy T& T::operator=(const T&); Copies all constructor or move // myFunc resolved via argument-dependent lookup (ADL) assignment members assignment // since it is the same namespace as the argument myFunc( exmpl::MyClass() ); // In the following statement, the << operator is resolved No explicitly declared copy // via ADL. Since one of its arguments (std::cout) is in Move T::T(T&&); Moves all constructor, copy assign- // the namespace 'std', the compiler is able to resolve constructor members ment, move assignment, or // the operator to std::operator<<(std::ostream, const char *) destructor std::cout << "Goodbye\n"; return 0; No explicitly declared copy } Move Moves all constructor, copy assign- T& T::operator=(T&&); assignment members ment, move constructor, or destructor Lambda Expressions Used to create function objects (functors) No explicitly declared Destructor T::~T(); Does nothing • The return type of a lambda expression can be either specified explicitly destructor via the trailing-return-type or deduced by the compiler from the return The default and delete keywords can be used when declaring special member functions (e.g., statement. default constructor, destructor, copy constructor, copy assignment, move constructor, and • The type of a lambda expression is a unique, unnamed, nonunion class type move assignment). called the closure type, which overrides the function call operator. class Complex – The closure type will have a nonstatic data member for each object that { the lambda expression captures by value. public: • In the example that follows, a lambda function is used as a predicate in a Complex() = default; // default constructor call to the standard template library algorithm std::count_if(). Complex(Complex const&) = default; // copy constructor Complex& operator=(Complex&) = default; // copy assignment • The capture clause is empty, meaning that no variables are being captured. Complex(Complex&&) = delete; // move constructor • The lambda expression has a single parameter in its parameter list: an int. Complex& operator=(Complex&&) = delete; // move assignment – An int must be used in this example because int is the value type of the ~Complex() = default; iterators passed to count_if(). private: – The return type of the lambda expression is deduced (as bool) from its double r; return statement. double i; Example: }; int countPositiveIntegers(std::vector<int> const & vec) { return std::count_if(vec.begin(), vec.end(), [](int i){ return i > 0;} //lambda function Function Overloading ); } • A function’s signature is determined by its name and the number, order, and type of its parameters. A function’s return type is not part of its signature. The lambda-introducer Capture Meaning • Function overloading is accomplished by declaring more than one function in the same scope [lambda-captureopt] [&] Capture any used variables by reference having the same name but different signatures. specifies the variables [=] Capture any used variables by value/copy – Overloaded functions must differ by the number and/or types of parameters, or in the case of that are “captured” by member functions, by their constness. the lambda expression. [identifier] Capture variable by value – Overloaded functions are allowed to have different return types; however, functions cannot The lambda-capture [identifier...] Capture parameter pack by value be overloaded based on return type. Declaring multiple functions with the same name in the may be empty or may [& identifier] Capture variable by reference same scope that differ only in return type is not allowed. contain one or more [& identifier…] Capture parameter pack by reference • Overloaded functions must be in the same scope. A member function in a base class cannot be captures. Each capture [& identifier= Capture variable by reference and overloaded by adding a member function to one of its derived classes, since the two functions may be one of the initializer] initialization are in different class scopes. following: [this] Capture current object by reference Example: [*this] Capture current object by value #include <vector> class Room {}; Copy/Move – Temporary objects are rvalues and can be implicitly moved // type alias Copy/Move Semantics from. using RoomId = int; • Objects can be copied by using a – Lvalues can only be moved class Building copy constructor or by using a from explicitly by using the { copy assignment operator. std::move() function, which public: – For large objects, a copy can be essentially implements a cast to // overloading based on number and/or an expensive operation. There- an rvalue. // types of parameters fore, the compiler will do its best – Objects are moved by using a Room& addRoom(); to eliminate unnecessary copies move constructor or a move as- Room& addRoom(Room const& room); in a process called copy elison. signment operator. // overloading based on constness • There are many situations in which – In order to gain a performance Room& getRoom(RoomId roomId); the original object is not needed benefit from moving, an object Room const& getRoom(RoomId roomId) const; after the copy is made. In such must have member pointers to private: cases, the object can be moved other dynamically allocated std::vector<Room> rooms; instead of copied. objects. }; 4 Type Conversion • C++ is a strongly/strictly typed language; a code smell and usually indicates a – C++ allows implicit (automatic) type warnings may be enabled via com- however, C++ gives users great power design problem. conversion between different types of piler command line options (e.g., to control (and even dictate) type » The following explicit type conver- fundamental and user-defined types. -Wconversion in the case of gcc). transformations. sion mechanisms are supported: Implicit type conversion is what allows » Implicit type conversion is enabled – Type transformations may be per- ♦ C-style cast: ( an int (integer) to be passed as an argu- for user-defined types via: formed automatically and silently by ♦ Functional cast (alternate syntax ment to a function that takes a long int ♦ Conversion constructors: the compiler (implicit type conver- ♦ fcoorn Cst-_sctyalset :c Fasotr) converting a const warigthuomuet nhta.ving to explicitly convert the Constructors declared without the sion) without warning the user (unless type to a mutable type (removes » Implicit conversions between funda- explicit keyword such warnings are enabled), leading constness) ♦ User-defined conversion functions mental types do carry a certain de- some to mistakenly believe that C++ is ♦ static_cast: For explicitly specify- » Implicit type conversion of user- gree of risk. For example, assigning weakly typed. ing an implicit conversion (or defined types can be disabled via an integer having a value of -1 to – There are several mechanisms that reversing such a conversion); able the explicit keyword. If the explicit a variable of type 32-bit unsigned allow users to control how and when tpoe ruftoilrimze c eoxnpvleicrsitio cnonstructors to int is equivalent of assigning a keyword is added to a constructor or types can be transformed. ♦ dynamic_cast: For safe value of 4294967295. user-defined conversion function, the – Explicit type conversion allows users down-casting from a base class ♦ This is probably not the intended constructor or conversion must be to explicitly convert an object of one pointer/reference to a derived class behavior. By default, modern explicitly specified. type to an object of another type. pointer/reference compilers do not warn of potential ♦ User-defined conversion functions » Use of explicit casting should be ♦ reinterpret_cast: For low-level casts issues that can be caused by should almost always be declared avoided, when possible. Excessive between unrelated types (can be implicit type conversions between as explicit to avoid accidental use of casting should be considered dangerous and should be avoided) fundamental types; however, such implicit conversion. Example of the various type conversion mechanisms: c = Complex{1}; void example() { // explicit conversion from complex to int class Complex int i = (int)Complex(); { i = static_cast<int>(Complex{1,1}); public: // Note use of C-style explicit conversion // implicit conversion from complex to int // of some arguments from int to double // i = complex(); // error: will not compile Complex() : real{0.0}, img{0.0} {}; Complex(double r) : real{r}, img{0.0} {}; class SpecialComplex : public Complex Complex(double r, double i) : real{r}, img{i} {}; { explicit Complex(int r, int i) : public: real{(double)r}, img{(double)i} {}; SpecialComplex(double r, double i) : explicit Complex(int r) : Complex(r,i) {}; real{(double)r}, img{0.0} {}; }; // user-defined conversion to int explicit operator int() const { SpecialComplex sc{1,1}; return (int)sqrt(real*real+img*img); }; // virtual destructor is needed because we // implicit conversion (upcast) from SpecialComplex ref // use of dynamic_cast below // to Complex ref virtual ~Complex() {}; Complex const & cr = sc; private: double real, img; // downcast from base to derived class }; SpecialComplex const & sc2 = // implicit conversion of initializer list dynamic_cast<SpecialComplex const &>(cr); // of double to complex Complex c = {1.0,1.0}; // assign base class ref to derived class ref // sp2 = cr; // error: will not compile // implicit conversion of initializer list // of int to complex // initialize a non-const ref from a const ref // c = {1,1}; // error: will not compile // by removing constness // c = {1}; // error: will not compile SpecialComplex & sc3(const_cast<SpecialComplex &>(sc2)); // explicit construction of complex from // initialize a const ref from non-const ref // initializer list of int // SpecialComplex & sc4(sc2); // error: will not compile c = Complex{1,1}; } Operator Overloading OPERATOR CLASS MEMBER NONMEMBER stream insertion N/A friend std::ostream& operator<<(std::ostream&, T const preincrement T& T::operator++(); friend T& operator++(T&); &); postincrement T T::operator++(int); friend T operator++(T&,int); stream extraction N/A friend std::istream& predecrement T& T::operator--(); friend T& operator--(T&); operator>>(std::istream&, T&); postdecrement T T::operator--(int); friend T operator--(T&,int); function call T2 operator()(…); N/A unary plus T T::operator+() const; friend T operator+(T const &); Note: Function call operator unary minus T T::operator-() const; friend T operator-(T const &); overloads may have arbitrary return types and arguments. addition T T::operator+(T2 const &) friend T operator+(T const &, T2 Used to implement functors (aka const; const &); function objects) subtraction T T::operator-(T2 const &) const; friend T operator-(T const &, T2 less than bool operator<(T const &) const; friend bool operator<(T const&, T const &); const &); multiplication T T::operator*(T2 const &) friend T operator*(T const &, T2 less or equal bool operator<=(T const &) friend bool operator<=(T const&, T const; const &); const; const &); division T T::operator/(T2 const &) const; friend T operator/(T const &, T2 greater than bool operator>(T const &) const; friend bool operator>(T const&, T const &); const &); modulo T T::operator%(T2 const &) friend T operator%(T const &, T2 greater or equal bool operator>=(T const &) friend bool operator>=(T const&, T const; const &); const; const &); bitwise AND T T::operator&(T2 const &) friend T operator&(T const &, T2 equal bool operator==(T const &) friend bool operator==(T const&, T const; const &); const; const &); bitwise OR T T::operator|(T2 const &) const; friend T operator|(T const &, T2 not equal bool operator!=(T const &) friend bool operator!=(T const&, T const &); const; const &); bitwise NOT T T::operator~() const; friend T operator~(T const &); array subscript T::value_type& operator[] N/A bitwise XOR T T::operator^(T2 const &) friend T operator^(T const &, T2 (std::size_t); const; const &); T::value_type const & operator[] bitwise left shift T T::operator<<(T2 const &) friend T operator<<(T const &, T2 (std::size_t) const; const; const &); not bool operator!() const; N/A bitwise right shift T T::operator>>(T2 const &) friend T operator>>(T const &, T2 Note: Should return the inverse const; const &); of the user-defined conversion copy assignment T& T::operator=(T const &); N/A function: explicit operator bool() const; move assignment T& T::operator=(T const &&) N/A noexcept; 5 Operator Overloading (continued ) • C++ operators for operands • Defining new operators is not Virtual Functions, Function » An interface is a set of method signatures that of user-defined types may be supported. define the ways in which subtype polymorphic Overriding & Interfaces overloaded in order to allow • Operator overloads may be code can interact with objects that implement the user-defined types to behave like declared as class members or as • Virtual function (virtual method): Member function interface. fundamental types in regard to the nonmember friends. that is invoked via dynamic dispatch • Derived concrete classes that implement the interface operators that are overloaded. – When overloading an operator • Dynamic dispatch: Mechanism by which an defined by the Shape abstract class can be declared – When a user-defined type for a class using a nonmember implementation of a function is selected and called at as follows: overloads an operator, the be- function, the function is often run-time based on the type of the object on which the class Circle : public Shape havior of that operator should made a friend function so that virtual member function is invoked { be consistent with expected/ it may access internals of the Example of a virtual function declared using the void draw() override final; conventional behavior for that class. virtual keyboard: }; // Shape is an abstract class operator. – To avoid having to make a // containing a pure virtual function Override & Final Keywords – It is best not to overload an nonmember operator overload class Shape • Use of the override keyword is optional but operator unless there is an a friend, the nonmember { recommended, since it allows the compiler to catch expectation that the operator operator overload can be virtual void draw() = 0; common mistakes, such as declaring the virtual }; should apply naturally to the implemented in terms of the function in the derived class using a function • In the example above, the Shape class declares a user-defined type. corresponding member opera- signature that does not match the signature of the virtual method called draw. The “=0;” at the end – Most operators can be over- tor overload. virtual function in the base class. of the virtual function declaration indicates that the loaded. The only operators that – The table on p. 5 shows how to Shape class will not provide an implementation • In order to override a virtual method, the function cannot be overloaded are declare various kinds of opera- of the draw method. Rather, classes derived from signature of the virtual method in the derived class sizeof :: . ?: tor overloads for a class T. Shape must provide the draw function in order to be must exactly match the signature of the virtual method Operator overloading example: instantiable. in the base class. Specifying the override keyword #include <iostream> • By declaring a member function to be virtual in a allows the compiler to enforce this rule. ##iinncclluuddee <<vaelcgtoorri>thm> base class, Shape forces that member function to be • The use of the final keyword is also optional. The final virtual in derived classes whether or not the function keyword specifies that any classes derived from Circle template <typename T> class vec is declared as virtual in the derived class. are not allowed to override the draw method. { std::vector<T> v; • A class containing at least one pure virtual function is • If the object model calls for different types of circles known as an abstract class, meaning that it cannot be (e.g., SolidCircle and HollowCircle) that are derived public: instantiated. from the Circle class and are drawn differently, then // default constructor vec() {}; – Abstract classes are used to define interfaces. you would not want to use the final keyword here. // constructor to reserve size v/e/c (csoinzset_rtu csti zfer)o m: ivn(istiizael)i z{e}r; list Polymorphic Destruction & Virtual » When deleting derived objects via pointers to vec(std::initializer_list<T> l) : v{l} {}; Destructors their base classes, resource leaks will occur // construct from std::vector unless the base class is declared to have a vec(std::vector<T> arg) : v{arg} {}; • Subtype polymorphic code is written in terms of virtual destructor. // copy constructor vec(vec const & arg) : v{arg.v} {}; pointers and/or references to base classes that point or Example: // move constructor refer to objects of derived classes. struct Shape vec(vec const && arg) : v{std::move(arg.v)} {}; – In such code, it is common to delete objects of de- { /v/e cc&o poyp earsastiogrn=m(evnetc const & rhs) { rived classes via pointer to base classes, in which /vi/r tvuiarlt u~aSlh adpees(t)r u{c tsotrd::cout << "~Shape\n"; } if (this != &rhs) { case it is critically important to declare the base }; v = rhs; class’s destructor as a virtual function. } return *this; • In the following example, two derived objects (a struct Circle : public Shape } Circle and a Square) are added to a vector of a unique { // move assignment pointer. Note that the unique pointers contain pointers // virtual destructor vec& operator=(vec && rhs) noexcept { to the base class (Shape). ~Circle() override { std::cout << "~Circle\n"; } i f ( tvh i=s s!t=d :&:rmhosv)e ({rhs.v); – When the main function returns, the vector is }; } destroyed, which results in the unique pointers return *this; struct Square : public Shape } contained in the vector being destroyed, which { // addition in turn causes the shape objects (allocated on the // virtual destructor friend vec operator+(vec const& lhs, vec const & rhs) { heap) to be deleted. ~Square() override { std::cout << "~Square\n"; } if (lhs.v.size() != rhs.v.size()) – When the unique_ptr deletes its contained object, }; throw std::invalid_argument(""); vec result(lhs.v.size()); it does so by invoking the delete operator on a std::transform( lhs.v.begin(), lhs.v.end(), pointer to the base class (Shape). int main() rhs.v.begin(), result.v.begin(), » The use of a virtual destructor is required { [](T l, T r){return l + r;} std::vector<std::unique_ptr<Shape>> shapes; ); here in order to assure that all resources as- return result; sociated with the derived objects get cleaned shapes.emplace_back(std::make_unique<Circle>()); } up properly. By declaring the base class as shapes.emplace_back(std::make_unique<Square>()); // stream insertion friend std::ostream& having a virtual destructor, it ensures that when } operator<<(std::ostream& os, vec const & v) { the destructor is called, the derived object’s i f ( !avu.tvo. eim{pvt.yv(.)b)e g{in()}; destructor is called first. This can be seen in the O~Cuitrpculte: os << *i; output of the example, which shows that first ~Shape while (++i!=v.v.end()) { the derived object’s destructor is called, then the ~Square os << "," << *i; base object’s destructor is called. ~Shape } } } return os; Templates Point(T _x, T _y) : x(_x), y(_y) {} } ; • Generic code that can act on any type in a type-safe TT xy;; manner as long as the type meets certain requirements }; int main() { implied by the template // template variable vec<double> v1{1,2,3}; • Can be used to define classes, functions (which may template<class T> vec<double> v2{1,1,1}; be member functions), and variables constexpr T pi = T(3.1415926535897932385L); – Template member functions cannot be virtual int main(int argc, char **argv) { avu1t o= vs3t d=: :vm1o v+e (vv23;); functions. double PI = pi<double>; #include <iostream> std::cout << "v1 = [" << v1 << "]\n"; #include <type_traits> const Point origin(0,0); std::cout << "v3 = [" << v3 << "]\n"; // template function for (long i=1; i<10; ++i) return 0; template<typename T> T factorial(const T& n) { { } return n<2 ? 1 : n * factorial(n-1); } std::cout << “Factorial of [“ << i << “] = [“ << factorial(i) Output: // template class << “]” << std::endl; v1 = [2,3,4] template<typename T> class Point } v3 = [] { return 0; public: } U.S. $7.95 Author: Scott Smith NOTE TO STUDENT: This guide is intended for informational purposes only. Due to its condensed format, this guide cannot cover every aspect of the subject; rather, it is intended for use in conjunction with course work and assigned texts. BarCharts Publishing, Inc., its writers, editors, and design staff are not responsible or liable for the use or misuse of the information contained in this guide. All rights reserved. No part of this publication may be reproduced or transmitted in any form, or by any means, electronic or mechanical, including photocopying, recording, or any information storage and retrieval system, without written permis- sion from the publisher. Made in the USA ©2019 BarCharts Publishing, Inc. 0519 6

See more

The list of books you might like

Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.