因为平时经常遇到C++,以后的课程应该也免不了要用,学一下C++。
参考用书:C++ Primer Plus(Sixth Edition),作者:Stephen Prata
I have learned the programming language C already, thus I’ll only take down new grammars and features in C++ in my notes.
Also, all the Chinese versions I’ve found are scanned version, but I find an English version which is not scanned. Therefore I’ll just use the English version. A chance to practice my English, not bad!
Chpt 1. Getting Started with C++
C++ is a superset of C. C++ joins 3 separate programming categories: the procedural language, the object-oriented language and generic programming.
C Programming Philosophy
In general, computer languages deal with two cocepts–data and algorithms. Like most mainstream languages when C was created, C is a procedural language. That means is emphasizes the algorithm side of programming.
C includes features to facilitate structured programming approach, making it relatively easy to read and modify a program.
Top-down design was another feature of C. The idea is to break a large program into smaller, more manageable tasks. C uses programming unit called functions to implemente this idea.
The C++ Shift: Object-Oriented Programming
Unlike procedural programming, which emphasizes algorithms, OOP emphasizes the data. The idea is to design data forms that correspond to the essential features of a problem.
In C++, a class is a specification describing such a new data form, and an object is a particular data structure constructed according to that plan.
The OOP approach to program design is to first design classes, then proceed to design a program using objects of those classes. This process of going from a lower level of organization(such as classes) to a higher level(such as program design) is called bottom-up programming.
There are other features of OOP such as information hiding, polymorphism, inheritance and etc.
C++ and Generic Programming
The term generic refres to code that is type independent. Generic programming involves extending the language so that you can write a function for a generic type once and use it for a variety of actual types.
Chpt 2. Setting Out to C++
Namespaces
If you use iostream
instead of iostream.h
, you should use the following namespace directive to make the definitions in iostream
available to your program:
using namespace std;
This is called a using
directive. Namespace support is a C++ feature that combines pre-existing code from several vendors and to help organize programs. One potential problem is that you might use two prepackaged products that both have a function called wanda()
. The namespace facility lets a vendor pakcage its wares in a unit called a namespace so that you can use the name of a namespace to indecate which vendor’s product you want. So Microflop Industries could place its definitions in a namespace called Microflop
. Then Microflop::wanda()
could denote Microflop’s version of wanda()
. Similarly, Piscine::wanda()
could denote Piscine Corporation’s version of wanda()
.
Thus, you can omit the using
directive and, instead, code in the following style:
std::cout << "Come up and C++ me some time.";
std::cout << std::endl;
The following line means you can use names defined in the std
namespace without using the std::
prefix:
using namespace std;
C++ Output with cout
cout << "Come up and C++ me some time."
The <<
notation indicates that the statement is sending the string to cout
; the symbols point the way the information flows. cout
is a predefined object that knows how to display a variety of things, intcluding strings, numbers and individual characters. Thus, you can say that it inserts a string into the output stream.
Using cin
cin >> carrots;
Just as C++ considers output to be a stream of characters flowing out of the program, it considers input to be a stream of characters flowing into the program.
Chpt 3. Dealing with Data
Naming Rules
One rule is worth noticing:
Names beginning with two underscore(_) characters or with an underscore character followed by an uppercase letter are reserved for use by the implementation–that is, the compiler and the resources it uses. Names beginning with a single underscore character are reserved for use as global identifiers by the implementation.
Using a name such as __time_stop
or _Donut
doesn’t produce a compiler error; instead, it leads to undefined behavior. In other words, there’s no telling what the result will be.
The sizeof
Operator and the climits
Header File
You can apply the sizeof
operator to a type name or to a variable name.
When you use the sizeof
operator with a type name, such as int
, you enclose the name in parentheses. But when you use the operator with the name of the variable, such as n_short
, parentheses are optional.
The climits
header file defines symbolic constants to represent type limits.
Integer Literals
An integer literal, or constant, is one you write out explicitly, such as 212 or 1776. C++, like C, lets you write integers in three different number bases: base 10, base 8, and base 16.
C++ uses the first digit or two to identify the base of a number constant:
- 1-9: decimal(base 10)
- 0: octal(base 8)
- 0x or 0X: hexadecimal(base 16)
If you want to display a value in headecimal or octal form, you can use cout
manipulators dec
, hex
, and oct
to display integers in decimal, hexadecimal, and octal formats, respectively.
wchar_t
, char16_t
and char32_t
The wchar_t
type is an integer type with sufficient space to represent the largest extended character set used on the system. This type has the same size and sign properties as one of the other integer types, which is called the underlying type. The underlying type depends on the implementation.
Because the sign and size of wchar_t
can vary from one implementation to another, C++11 introduces the types char16_t
, which is unsigned and 16 bits, and char32_t
, which is unsigned and 32 bits. C++11 uses the u
prefix for char16_t
character and string constants, like u'C'
and u"be good"
. Similarly, it uses the U
prefix for char32_t
constants, like U'R'
and U"dirty rat"
.
A member function: cout.put()
The cout.put()
function is the first example of an important C++ OOP concept, the member function. A member function belongs to a class and describes a method for manipulating class data. The cout
is an object of class ostream
. The class has a member function named put()
. We can use the function with a particular object of the class, such as cout
object.
To use a class member function with an object of that class, simply use a period to combine the object name(cout
) with the function name(put()
).
We’ll learn “Objects and Classes” in Chapter 10. Now the only classes we have encountered are
istream
andostream
classes.
The const
qualifier
C++ uses const
to handle symbolic constants. For example, const int Months = 12
initialized a constant named Months
with value of 12.
Writing Floating-Point Numbers
C++ has two ways of writing floating-point numbers. The first is the custom way, like 3.14159
. The second method is called E notation, which is like 3.14E-6
(= 0.00000314
). The -6 is called an exponent, and the 3.14 is termed the mantissa.(You can use both E or e in E notation)
Floating-Point Constants
By default, floating-point constants such as 8.24 and 2.4E8 are type double
. If we want a constant to be type float
, we can use an f
or F
suffix. For type long double
, we can use an l
or L
suffix.
Conversion
When you try to combine mixed types, C++ converts all the concerned types to the same type.
C++ empowers us to force type conversions explicitly vis the type cast mechanism.
You can use (typename) value
or typename (value)
to complete type cast. The former is traditional C form of type cast, whereas the second form is pure C++. The idea behind the new form is to make a type cast look ike a function call. This makes type casts for the built-in types look like the type conversions you can design for user-defined classes.
C++ also introduces 4 type case operators that are more restrictive in bow they can be used. Ot the four, the static_cast<>
operator, can be used for converting values from one numeric type to another. Usage: static_cast<typename> value
. The idea behind is to be more restrictive than the traditional type cast.
auto
Declarations in C++11
C++11 introduces a facility that allows the compiler to deduce a type from the type of an initialization value. For this purpose it redefines the meaning of auto
, a keyword dating back to C, but one hardly ever used.
auto n = 100; // n is int
Chpt 4. Compound Types
Arrays
You can use a comma-separated list of values (the initialization list) enclosed in braces to initialize an array, like int yamcosts[3] = {20, 30, 5};
. However, you can only use the initialization form when defining the array. You cannot use it later() and you cannot assign one array wholesale to another(int hands[4]; hands[4] = {5, 6, 7, 9};
).int cards[4] = {1, 2, 3, 4}; hands = cards;
You can let the compiler counter number of elements in an array while initializing:
short things[] = {1, 5, 3, 8};
int num_elements = sizeof things / sizeof (short);
C-style Strings
C++ has two ways of dealing with strings. The first is C-style string, like char name[4] = {'S', 'a', 'm', '\0'};
; the second is using C++ string
class.
For C-style strings, you can just initialize it without denoting the number of characters:
char fish[] = "Bubbles"; // let the compiler count
A tricky point about cin
is that cin
uses whitespace(spaces, tabs, and newlines) to delineate a string. This means that cin
only reads one word when it gets input from a character array. The program instr1.cpp shows this.
To read input strings a line at a time instead of a word, you should use istream
(cin
is its object) class member functions getline()
and get()
. The difference is, after reading a line, getline()
discards the newline character, whereas get()
leaves it in the input queue.
get(name, ArSize)
reads input characters from keyboard and stops when input reaches its end or input is longer than ArSize
. Note that the character '\n'
will be left in the inpiut queue.
A single get()
reads one character a time. We can use it to absort the '\n'
character left by the above function:
cin.get(name, ArSize); // read first line
cin.get(); // read newline
cin.get(dessert, ArSize); // read second line
Another way to use get()
is to concatenate, or join, two class member functions, as follows:
cin.get(name, ArSize).get(); // concatenate member functions
This is possible because cin.get(name, ArSize)
returns the cin
object.
Use string
Class
Just use
string str1;
to declare a string. We can also use cin
and cout
to assign or print the value of a string.
The string
class makes it simpler for some operations to be done. For example, you can assign a string object directly to another. Also you can combine strings using the operator +
. An advantage of using string
class is that you don’t have to worry about oversizing. string
objects will automatically resize its size to fit in your input or your operation.
We can use member functions size()
of string
class to get the length of a string, which is equivalent to the strlen()
function from the <cstring>
header file(the older <string.h>
).
We can use getline(cin, stringname)
to get a string from the keyboard. Note that cin
is an argument of the function, which indicates that this getline()
function is not the member function method from istream
class. It takes cin
as an argument that tells it where to find the input. Also, there isn’t an argument for the size of the string because the string
object automatically resizes to fit the objects, as we’ve discussed above.
Structure and Union
You’ve defined a strcture inflatable
:
struct inflatable{
char name[20];
float volume;
double price;
};
Then you can create variables of type inflatable
:
inflatable hat;
Notice that you don’t have to write struct
before structure name inflatable
, which is required in C.
You can use string
class members within structure definition. Just move the using
directive before structure definition.
The usage and function of union in C++ is the same as is in C.
Enumerations
Enumeration is defined as follows:
enum spectrum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};
It establishes red
, orange
, yellow
, and so on, as symbolic constants for the integer values 0-7. These constants are called enumerators.
Notice that only assignment operator is defined for enumerations. In particular, arithmetic operations are not defined. However, enumerators can be automatically converted to int
type, but int
types are not converted automatically to the enumeration type:
int color = blue; // valid, spectrum type promoted to int
spectrum band;
band = 3; // invalid, int not converted to spectrum
color = 3 + red; // valid, red converted to int
Allocating Memory with new
In C, you can allocate memory with the library function malloc()
. You can still so so in C++, but C++ provides a better way: the new
operator.
int *pn = new int;
The new int
part tells the program you want some new storage suitable for holding an int
. The new
operator uses the type to figure out how many bytes are needed. Then it finds the memory and returns teh address.he
Freeing memory with delete
You can free memory with delete
:
int *ps = new int;
...
delete ps;
Use new
to Create Dynamic Arrays
int *psome = new int[10];
Use delete
to Free Dynamic Arrays
delete [] psome;
Pointer and Array
Array name denotes the address of the starting element of the array. We have that pointername[i] == *(pointername + i)
. Thus, in many cases we can use pointer names and array names in the same way.
However, there are two major differences between pointer names and array names. The first one is that array name is a constant, so you cannot change it. But pointername is changeable:
pointername = pointername + 1; // valid
arrayname = arrayname + 1; // not allowed
A second difference is that applying the sizeof
operator to an array name yields the size of the array, even if the pointer points to an array. But applying the sizeof
operator to array names produce the size of the array. For example:
double wages[3] = {10000.0, 20000.0, 30000.0};
double *pw = wages;
cout << sizeof(wages) << " = size of wages array\n";
cout << sizeof(pw) << " = size of pw pointer\n";
Running result:
24 = size of wages array
4 = size of pw pointer
Pointer and String
char animal[20] = "bear"; // animal holds bear
char *ps = animal;
cout << animal << " at " << (int *) animal << endl;
cout << ps << " at " << (int *) ps << endl;
Output:
bear at 0x61fdf0
bear at 0x61fdf0
Normally, if you give cout
a pointer, it prints an address. But if the pointer is type char *
, cout
displays the pointer-to string. If you want to see the address of the string, you have to type cast the pointer to another pointer type, such as int *
, as the example above shows.
The vector
Template Class
The vector
template class is similiar to the string
class in that it is a dynamic array. Basically, it’s an alternative to using new
to create a dynamic array.
We’ll pay attention to 5 aspects of the vector
class:
- To use a
vector
class, you need to include thevector
header file. - The
vector
identifier is part of thestd
namespace, so you can use ausing
directive, ausing
declaration, orstd::vector
. - Templates use a different syntax to indicate the type of data stored.
- The
vector
class uses a different syntax to indicate the number of elements.
using namespace std;
vector<int> vi; // create a zero-size array of int
int n;
cin >> n;
vector<double> vd(n); // create an array of n doubles
The array
Template Class (C++11)
Compared to vector
, the built-in array type is a bit more efficient, but it comes at a cost of leesened convenience and safety. To solve this problem, C++11 adds the array
template class. To create an array
object, you need to include the array
header file. Also it is in namespace std
.
#include <array>
...
using namespace std;
array<int, 5> ai; // create array object of 5 ints
array<double, 4> ad = {1.2, 2.1, 3.43, 4.3};