User:Dan Polansky/C++ programming

What follows is to complement C++ Programming wikibook.

C-style casting edit

At a glance:

// Float to int
float pi = 3.141592;
int truncated_pi = (int)pi; // --> 3
float neg_pi = -3.141592;
int truncated_neg_pi = (int)neg_pi; // --> -3
float almost_two = 1.9;
int truncated_almost_two = (int)almost_two; // --> 1
  
// Char to int
char my_char = 'A';
int char_as_int = (int)my_char; // --> 65 -- ASCII for 'A'

// Int to float to get float division
float division  = 5/truncated_pi;          // --> 1.000000
float division2 = 5/(float)truncated_pi;   // --> 1.666667

// Float to int reinterpret cast - requires a pointer
int *pi_reinterpret_as_int = (int*)π    // maybe 0x40490fd8
int pi_reinterpret_as_int2 = *(int*)π   // maybe 0x40490fd8

// Int to uint reinterpret cast - requires a pointer
int neg_1 = -1;
unsigned int *int_reinterpret_as_uint = (unsigned int*)&neg_1; // maybe 0xffffffff

// Unsigned to signed - value out of range
unsigned int large_uint = 0xfffffffe;
int large_uint_turned_signed = (int)large_uint; // maybe -2

// Print
printf("%i, %i, %i, ", truncated_pi, truncated_neg_pi, truncated_almost_two);
printf("%i, %f, %f, ", char_as_int, division, division2);
printf("%x, %x, ", *pi_reinterpret_as_int, *int_reinterpret_as_uint);
printf("%i", large_uint_turned_signed);

See also C_Programming/Simple_math#Cast_operators.

Links:

C++-style casting edit

At a glance:

// Float to int
float pi = 3.141592;
int truncated_pi = static_cast<int>(pi);         // --> 3
float neg_pi = -3.141592;
int truncated_neg_pi = static_cast<int>(neg_pi); // --> -3
float almost_two = 1.9;
int truncated_almost_two = static_cast<int>(almost_two); // --> 1
  
// Char to int
char my_char = 'A';
int char_as_int = static_cast<int>(my_char); // --> 65 -- ASCII for 'A'

// Int to float to get float division
float division  = 5/truncated_pi;                         // --> 1.000000
float division2 = 5/static_cast<float>(truncated_pi);     // --> 1.666667

// Float to int reinterpret cast - requires a pointer
int *pi_reinterpret_as_int = reinterpret_cast<int*>(&pi); // maybe 0x40490fd8
int pi_reinterpret_as_int2 = *reinterpret_cast<int*>(&pi); // maybe 0x40490fd8
//int pi_reinterpret_as_int3 = reinterpret_cast<int>(pi); // compilation error
  
// Int to uint reinterpret cast - requires a pointer
int neg_1 = -1;
unsigned int *int_reinterpret_as_uint = reinterpret_cast<unsigned int*>(&neg_1); // maybe 0xffffffff
  
// Unsigned to signed - value out of range
unsigned int large_uint = 0xfffffffe;
int large_uint_turned_signed = static_cast<int>(large_uint); // maybe -2
  
// Print
printf("%i, %i, %i, ", truncated_pi, truncated_neg_pi, truncated_almost_two);
printf("%i, %f, %f, ", char_as_int, division, division2);
printf("%x, %x, ", *pi_reinterpret_as_int, *int_reinterpret_as_uint);
printf("%i", large_uint_turned_signed);

Above, const cast and dynamic cast are not covered.

Const cast is used to remove constness and more.

Dynamic cast is for pointers and references to instances of polymorphic classes, and enables to treat what is on the face of it available as a broad class as a narrower class. A class is polymorphic if it has at least one virtual method. A failed dynamic cast of a pointer returns null. An example:

class Tree {                    public: virtual void tree() { } };
class Conifer : public Tree {   public: void con() { printf("Con "); } };
class Pine : public Conifer {   public: void pine() { printf("Pine "); } };

Tree* my_tree = new Pine();
Conifer* my_con = dynamic_cast<Conifer*>(my_tree); // OK: in fact a pine
Pine* my_pine = dynamic_cast<Pine*>(my_tree);      // OK: in fact a pine
my_con->con();   // Method not accessible from my_tree
my_pine->pine(); // Method not accessible from my_tree

Tree* my_tree_only = new Tree();
Pine* my_pine2 = dynamic_cast<Pine*>(my_tree_only); // Bad: --> null

See also C++_Programming/Programming_Languages/C++/Code/Statements/Variables/Type_Casting#Explicit_type_conversion_(casting).

Links:

Zero initialization edit

What follows is tentative. Some variables and attributes are automatically initialized to zero. These are above all those with static storage duration. Objects with static storage duration include the following:

  • Global variables
  • Static variables outside of functions, global to a compilation unit
  • Static variables inside of functions
  • Static class attributes

These objects are stored neither on the stack nor on the heap. Static storage duration is not to be confused with static variable, declared so using the keyword static; a non-static global variable has static storage duration. Static storage duration stands in contrast with automatic storage duration (stack) and dynamic storage duration (heap).

The above may hold only for plain old data (POD); to be clarified.

The relevant part of the C++03 standard is section 3.6.2 Initialization of non-local objects.

Links:

Plain old data edit

As a first approximation, plain old data (POD) is C data as opposed to C++ data. This includes ints, floats, pointers, C structs, and arrays. An array of non-POD types is not plain old data. However, certain classes are plain old data as well. A struct or class that has a programmer-defined constructor, a destructor, or a virtual function is not plain old data; some other cases are not plain old data as well. C++11 offers std::is_pod template to find out, requiring #include <type_traits>.

Links:

Constructor call order edit

In sum, the body of the base class constructor first. A constructor of a derived class calls the constructors of its base classes before it starts executing its own body.

Thus, if class AppleTree derives from Tree, which derives from Plant, which derives from Thing, the order of executing the class constructor bodies upon instantiation of AppleTree will be this:

  • Thing
  • Plant
  • Tree
  • AppleTree

Note that the constructor invocation order is the opposite of the above. Thus, a contrast needs to be made between constructor invocation order and constructor body execution order. AppleTree is invoked first, and the very first thing it does is invoke Tree constructor, which invokes Plant constructor as the very first thing, which invokes Thing constructor as the first thing. Thing constructor handles its initializer list and executes its body, and then returns control to Plant constructor. Plant constructor handles its initializer list and then its body, and returns control to Tree constructor; etc.

For multiple inheritance, the picture is a little more complex: the multiple base classes are taken in the order of derivation, from left to right.

Links:

Template compilation edit

Template definitions have to be included (usually via #include) in the compilation units that use them, and thus are often placed into header files. The result may be that the compiler creates a duplication of template executable code in .o files of the separate compilation units that use a particular template instantiation, a duplication that is only removed by the linker. Some compiler suites use compilation strategies to avoid that duplication.

A technique called explicit instantiation can be used by the programmer to eliminate that duplication, generally resulting in reduced compilation time. It consists in marking one or more compilation units for inclusion of a particular template instantiation while marking other compilation units that use that instantion for exclusion and mere referencing of the code of that instantiation. The latter is ensured by adding the keyword extern to the explicit instantiation syntax. Thus, the compilation units in which an instantiation is marked for exclusion depend on other compilation units for this to work at the linking time.

Possible good location for this material: C++ Programming/Templates.

Links:

Interpreter edit

There exist approximate interpreters of C and C++, allowing interactive entry as if in a command shell.

Cint is one such interpreter, licensed under X11/MIT license. It can be currently downloaded from hanno.jp. Limitations of Cint are documented at cern.ch.

To use Cint, run it, and on its command line enter . (period) and press enter. Thereafter, you can have an interactive session:

cint.exe> mystr = "Hello" // ; is optional and the type is auto
(const char* 0x3ecdb8)"Hello"
cint.exe> mystr[0]
(char 72)'H'
cint.exe> *(mystr+1)
(char 101)'e'
cint.exe> sizeof(mystr)
(const int)4
cint.exe> float pi = 3.141592
cint.exe> *(int*)&pi
(int)1078530008
cint.exe> printf("pi cast %x\n", *(int*)&pi)
pi cast 40490fd8
(const int)17
cint.exe> puts("Hey")
Hey
(const int)0
cint.exe> int myarray[] = {1,2,3}
cint.exe> myarray[1]
(int)2
cint.exe> int nested[2][2] = {{1,2},{3,4}}
cint.exe> nested[1][1]
(int)4
cint.exe> for (int i=0;i<2;i++) { printf("%i\n",i); }
0
1
cint.exe> sin(4.0) // Some math from math.h but not all of it
(const double)(-7.56802495307928200e-001)
cint.exe> strlen("abc") // Some string functions
(const unsigned int)3

Naming conventions edit

Different naming conventions for variables, types, etc. are used by different organizations.

See also C++ Programming/Weblinks#C++ Coding Conventions.

Links:

Brace conventions edit

Some put the opening brace ({) on a separate line, some don't:

  • The K&R style seems to place the opening brace on a separate line for functions but not for control structures: W:Indentation style#K&R style.
  • GCC Coding Conventions do not seem to be explicit bout this, but code examples they provide place the opening brace of a function definition on a separate line. An example file is fixed-bit.c at github.com.
  • Google C++ Style Guide says that "The open curly brace is always on the end of the last line of the function declaration, not the start of the next line."
  • LLVM Coding Standards do not seem to be explicit about this, but code examples they provide do not place the opening brace of a function definition on a separate line. Example file: LLLexer.cpp at github.com.
  • Joint Strike Fighter Air Vehicle C++ Coding Standards place the braces on separate lines as per AV Rule 60.
  • Mozilla Coding Style indicates that Firefox uses Google Coding style for C++ code. As an example, nsBrowserApp.cpp at dxr.mozilla.org uses multiple styles.
  • Linux code base: fork.c at github.com places the opening bracket on a new line for functions but on the same line for control structures such as if.
  • Python C implementation: ceval.c at github.com seems to use the K&R style: opening brace on a new line for functions but not for control structures. This seems to match PEP 7 (Style Guide for C Code).
  • C Style and Coding Standards for SunOS from 1993 at cis.upenn.edu seem to use the K&R style.

Links:

External links edit