Inside Delphi 2006 (Wordware Delphi Developers Library)

C++ Language Basics

To learn about the basics of the C++ language, you should first create a C++Builder console application project. To do so, select File ® New ® Other to display the New Items dialog box, select the C++Builder Projects node in the Item Categories tree, and double-click the Console Application item on the right (see Figure 2-9). C++Builder projects, like all other projects, can also be created by double-clicking the appropriate item on the Tool Palette.

Figure 2-9: Creating a C++Builder console application project

After you click OK on the New Items dialog box or double-click the Console Application item in the C++Builder Projects category on the Tool Palette, the IDE displays the New Console Application wizard, which allows you to choose between a C and a C++ console application project (see Figure 2-10).

Figure 2-10: The New Console Application wizard

Since a basic C console application (at least the way basic output is achieved) is syntactically more similar to a Delphi console application than a C++ console application is, let's first create a C console application. To do so, select the C radio button in the Source Type group box and uncheck all but the Console Application check box in the group box on the right. When the IDE finishes creating the project files and opens them in the IDE, select File ®Save All to save all project files to disk.

C/C++ Project Files

The IDE creates four files with the extensions .bdsproj, .bpf, .c, and .res. The .bdsproj, .bpf, and .res files are created for both C and C++ console application projects, and the .c source file is created when you create a C console application project. If you create a C++ console application project, the IDE creates a .cpp source file.

Although it contains no source code or configuration settings, the .bpf file, displayed in the IDE automatically after you create a new console application project (see Figure 2-11), is the most important file, because it alone gives us the ability to compile the console application project inside the IDE.

Figure 2-11: The .bpf file

The .bdsproj file in a C/C++ project is the same as in a Delphi project. It's an XML file that contains project configuration settings. The .res file is a resource file that contains the main icon for the application (see Figure 2-12). The .c file is the main source code file.

Figure 2-12: Delphi and C/C++ console applications

If you compile the application now, the IDE will create three more files: an .obj, a .tds, and finally the .exe file. The .obj file is the compiled version of the .c or .cpp source file, the .tds file contains debugger symbol information used for debugging, and the .exe file is of course the final executable.

Before we move on, you should note that Delphi console applications can also have a custom application icon, just like C++ console applications do. To add a custom application icon to a Delphi console application, you need to create or otherwise acquire a .res file that contains an icon resource called MAINICON (this is explained later in the book) and link it to the application using the $R compiler directive. For now, you can simply copy the  Project1.res file from a C++Builder console application project to your Delphi console application project and add the following line of code before the uses list:

{$R Project1.res}

Listing 2-17 shows the entire Delphi console application that uses the default C++Builder icon.

Listing 2-17: Delphi console application with the C++Builder icon

program Project1; {$APPTYPE CONSOLE} {$R Project1.res} uses SysUtils; begin WriteLn('Delphi Console Application with the C++Builder icon.'); ReadLn; end.

The Structure of a C/C++ Console Application

After you create a new C++Builder console application project, the IDE stores the necessary code that makes the application work in a .c or a .cpp file. In this case, the source code of the console application is stored in the  Unit1.c file. You can see this code in Listing 2-18. When you start typing this example (and others), remember that both C and C++ are case sensitive and that most of the identifiers you'll encounter in these languages are lowercase.

Listing 2-18: The source code of a C console application

//--------------------------------------------------------------------------- #include <stdio.h> #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused int main(int argc, char* argv[]) { return 0; } //---------------------------------------------------------------------------

Comments

Like Delphi, C++ supports both single-line and block comments. As you can see below, a single-line comment is written exactly the same in Delphi and C++, using two adjacent slashes:

// This is a Delphi/C++ single-line comment.

C++ also supports block comments. A block comment in C++ begins with the slash/asterisk combination and ends with the asterisk/slash combination:

/* This is a C++ block comment */ /* It can also stretch through several lines. */

Preprocessor Directives

Preprocessor directives in C/C++ start with the symbol # and are usually placed at the beginning of the source code file. The most useful preprocessor directive, which can be seen at the beginning of the source code, is the #include directive.

The #include directive is the C/C++ version of Delphi's uses list. It enables us to reuse existing code that resides in another source code file. Each #include directive only includes a single file. So, if you want to use routines that reside in several source code files, you must add an #include directive for each file:

#include <stdio.h> #include <conio.h> #include <stdlib.h>

There are two more preprocessor directives in the source code: #pragma hdrstop and #pragma argsused. You should always use the #pragma hdrstop directive because it boosts compiler performance, especially in large projects that consist of a large number of source code files and include a large number of common header files.

The #pragma hdrstop directive terminates the list of header files that should be precompiled. All header files above the #pragma directive are compiled once and then stored to disk. These precompiled headers drastically increase the speed of compilation because the compiler no longer has to parse the headers but simply loads the already parsed headers from disk. For best compiler performance, you should place common header files before the #pragma hdrstop directive and project-specific source code files (the ones you're working on) after it.

The only, and not so serious, downside of precompiled headers is the fact that they use a bit more disk space. In C++Builder 2006, all precompiled headers are, by default, cached to the vcl100.csm file located in the InstallDir\ lib directory, so you can check how much disk space the precompiled headers use on your machine. If you really miss the several megabytes used by the precompiled headers, you can completely disable the creation of precompiled headers in the Project Options dialog box (see Figure 2-13).

Figure 2-13: Precompilation settings

The #pragma argsused directive is automatically generated by the IDE to remove the warning message that tells us that we're not using the argc or argv parameters in the main function (see Figure 2-14). The directive is placed immediately above the main function because it only affects a single function, the one that follows in the source code. You can read more about functions and parameters in Chapter 5.

Figure 2-14: A console application compiled without the #pragma argsused directive

Note that, by default, you won't get the above warning messages even if you remove the #pragma argsused directive. You won't get the "Parameter is never used" warning because it is disabled in Project Options. To receive this and other warning messages, open the Project Options dialog box, select the Warnings node on the left, and then select the Enable all warnings radio button in the Warnings area to have the IDE display all warning messages.

Figure 2-15: Displaying all warning messages

The main Function

The main function in C/C++ console applications is the equivalent of the main begin-end block in Delphi applications — it's the place where C/C++ console applications begin executing:

int main(int argc, char* argv[]) { return 0; }

To execute a statement when the application starts, place it after the left brace (which denotes the beginning of a block in C/C++) and before the return statement. Although the main function's block ends with the right brace, you must place your statements before the return statement because the return statement terminates the execution of a function. In the case of the main function, the return statement terminates the execution of the entire console application. If you place a statement after the return statement, your statement will never be executed, and in fact, the compiler will issue a warning to notify you of this.

Figure 2-16: Error message when placing statements after the return statement

The value 0 that follows the reserved word return is the return value of the function. The main function returns 0 to indicate that it executed successfully. To notify the system that an error occurred during execution, you can return a non-zero value.

Standard C Output with printf

To output a piece of data to the console window in a C console application, you can use the printf statement, which is declared in the stdio.h header file. Note that strings in C and C++ are surrounded by double quotes, not by single quotes as in Delphi.

The following listing shows how to output a simple text message using the printf statement. (Note that redundant comments have been removed from the listing to save space.)

Listing 2-19: Basic text output with the printf statement

#include <stdio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { printf("Hello from C++Builder!"); return 0; }

If you run the application now, you'll undoubtedly notice that this console application too, like the basic Delphi console application, immediately closes after all statements in the main function have executed. In order to keep the console window visible, we need to use a statement similar to the ReadLn statement used in Delphi console applications.

To pause the execution of a C/C++ console application until the user presses a key, we can use the getch() function, which reads a character from the keyboard but doesn't display it on screen. To use the getch() function in your application, you have to include the conio.h header file using the #include directive. Don't forget to include it before the #pragma hdrstop directive.

The following listing shows the complete console application that remains on screen until the user presses a key to close it. The getch() function works better in this case since it finishes after the user presses any key, unlike ReadLn, which finishes only when the user presses the Enter key.

Listing 2-20: Using the getch() function to pause application execution

#include <stdio.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { printf("Hello from C++Builder!"); getch(); // wait until the user presses a key on the keyboard return 0; }

Standard C++ Output with cout

Now that you understand the structure of a C/C++ console application, we can start creating C++ console applications and output data to the screen the C++ way — using the cout object. Don't forget to select the C++ radio button on the New Console Application wizard to create a new C++ console application project. By selecting the C++ radio button, the IDE will generate a .cpp source file and will not automatically include the stdio.h header file, since it's not required in a C++ console application.

The following listing shows a very simple C++ console application that uses the cout object to output the string "Hello from C++Builder!" to the screen.

Listing 2-21: A simple C++ console application

#include <iostream.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { cout << "Hello from C++Builder!"; return 0; }

Although the way text is displayed with the cout object is a bit awkward at first, there's not much to it. To display text or other data using the cout object, you have to remember only two things:

The cout object normally works like the Write statement in Delphi — it displays text in the same line. To move the cursor to a new line, like Delphi's WriteLn statement does, you need to assign the endl (end line) manipulator to the cout object (this is much easier than it sounds).

The following code shows how to output text using the cout object and how to use the endl manipulator to move the cursor to a new line. Figure 2-17 shows the result of the code.

Figure 2-17: Displaying text with the cout object

Listing 2-22: Displaying several lines of text with cout

#include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { cout << "This is the "; cout << "first line."; // use the endl manipulator to write an "empty line" cout << endl; // simulate the WriteLn statement by writing the text first // and then the newline character to move to a new line cout << "This is the second line." << endl; cout << "This is the third line." << endl; cout << endl << endl; cout << "Press any key to continue..."; getch(); return 0; }

Fundamental Data Types

As you've already read earlier in this chapter, data types are used to define the memory size, value range, and allowable operations of a variable. Table 2-4 lists integer types, matching Delphi types, and their memory size and value range. Table 2-5 lists the real types, their memory size, and their range.

Table 2-4: C++ integer types

C++ Type

DelphiType

MemoryRequired (bytes)

Range

bool

Boolean

1

true/false

char

Shortint

1

–128..127

unsigned char

Char

1

0..255

short

Smallint

2

–32768..32767

unsigned short

Word

2

0..65535

long

Integer

4

–2147483648..2147483647

unsigned long

Cardinal

4

0..4294967295

int

Integer

4

–2147483648..2147483647

unsigned int

Cardinal

4

0..4294967295

__int64

Int64

8

–263..263–1

Table 2-5: C++ real types

C++ Type

Memory Required (bytes)

Range

float

4

1.18 x 10–38..3.4 x 1038

double

8

2.23 x 10–308..1.79 x 10308

long double

10

3.37 x 10–4932..1.18 x 104932

Variables

Variable declaration in C++ is somewhat different from that in Delphi. There are five basic differences:

The following example shows how to declare two variables for use in the main function.

Listing 2-23: Declaring variables in C++

#include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { // declare two variables int x; float f; // display the values of x and f variables cout << "x = " << x << endl; cout << "f = " << f << endl; getch(); return 0; }

If you run this application, you'll learn an important thing about Delphi and C++ variables: When a variable is declared, it is assigned a random value from memory (see Figure 2-18). So, before using a variable in either language, you should initialize the variable to a valid value.

Figure 2-18: Variables containing random values

The previous example shows how to declare variables the semi-Delphi way — at the beginning of a block — before all other statements. The following example, however, shows that it's valid to declare a variable anywhere in a block, as long as you don't try to use the variable before it's declared.

Listing 2-24: Declaring variables in C++, revisited

#include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { int i; cout << "i = " << i << endl; float f; cout << "f = " << f << endl; double d; cout << "d = " << d << endl; getch(); return 0; }

Initializing Variables

There are two ways a variable can be initialized in C++ (the first way is used most often):

data_type variable_name = initial_value; data_type variable_name (intial_value);

The example in Listing 2-25 illustrates both ways of variable initialization.

Listing 2-25: Initializing variables in C++

#include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { int i = 5; int j(10); cout << "i = " << i << " & j = " << j << endl; getch(); return 0; }

Assignment Operators

Even though the title suggests that C++ has more than one assignment operator, C++, like Delphi, only has one real assignment operator. Other assignment operators available are not pure assignment operators since they do more than just assign a value to a variable. The assignment operator in C++ is the equal sign:

int i; i = 2;

Another notable difference between Delphi and C++ is that the assignment operator can be used to assign a common value to multiple variables at once. Here's how you can assign the number 5 to four different variables (and how to declare several variables of the same type in the same source code line):

int a, b, c, d; a = b = c = d = 5;

Other available assignment operators are actually a mix of the main assignment operator and arithmetic operators (see Table 2-6). These are known as compound assignment operators.

Table 2-6: Basic compound C++ assignment operators

Operator

Meaning

AbbreviatedForm

StandardForm

+=

Add and assign

a += 2;

a = a + 2;

–=

Subtract and assign

a –= 2;

a = a – 2;

*=

Multiply and assign

a *= 2;

a = a * 2;

/=

Divide and assign

a /= 2;

a = a / 2;

%=

Get division remainder and assign

a %= 2;

a = a % 2;

The example in Listing 2-26 fully illustrates how to use compound assignment operators.

Listing 2-26: Using compound operators

include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { int i = 1; // increment i by 2 using the += compound operator i+=2; cout << i << endl; // i = 3 getch(); return 0; }

Arithmetic Operators

Table 2-7 shows both C++ and Delphi arithmetic operators and two minor differences between arithmetic operators in these two languages: C++ has only one division operator for integer and floating-point numbers and it has two operators not available in Delphi. Actually, the increment and decrement operators exist in Delphi, but as the Inc and Dec procedures (more on these procedures in Chapter 5).

Table 2-7: Arithmetic operators

C++ Operator

Delphi Operator

Description

+

+

Addition

Subtraction

/

div

Integer division

/

/

Floating-point division

%

mod

Modulo (remainder)

++

N/A

Increment

--

N/A

Decrement

The increment and decrement operators can be used to increment or decrement the value of a variable by one. The following example shows all three ways of incrementing a variable by one:

#include <iostream.h> #include <conio.h> #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { int a = 0; // the following statements do exactly the same thing, // increment the value of variable a by one a = a + 1; // a = 1 a += 1; // a = 2 a++; // a = 3 cout << "a = " << a << endl; // 3 getch(); return 0; }

The ++ operator in the above example is also known as the postincrement operator since it is written after the identifier. If the ++ operator is written before the identifier, it is known as the preincrement operator:

int a = 0; a++; // postincrement, a = 1 ++a; // preincrement, a = 2 a--; // postdecrement, a = 1 --a; // predecrement, a = 0

When the increment or decrement operators are used in a simple statement, as they are in the above code, there's no difference between the two. But the difference is clearly visible in an expression because the preincrement and predecrement operators change the value before the entire expression is evaluated, and the postincrement and postdecrement operators modify the value after the entire expression is evaluated. This means that when you use the postincrement or the postdecrement operator in an expression, it doesn't affect the expression at all.

Here's an example that shows the result of using the postincrement operator in an expression:

int b = 2; int sum = 0; sum = a + b++; // sum = 3 because a = 1, b = 2 // now b equals 3

But if we change the postincrement operator to the preincrement operator, the sum will be 4 because the preincrement operator will first increase the value of the b variable to 3, then add the value of the b variable to the a variable, and finally assign the sum of a and b to the left side, the sum variable:

int a = 1; int b = 2; int sum = 0; sum = a + ++b; // sum = 4 because a = 1, b = 3

Believe it or not, the space in the above substatement is extremely important. If you remove the space from the statement, you'll get an incorrect result and a bug in your code. Here's the statement without a space:

sum = a+++b;

You'll get an incorrect result because the C++ compiler no longer sees this statement as the variable plus the preincremented b variable but as the postincremented a variable plus the b variable:

// this is what the compiler thinks you want when you omit whitespace sum = a++ + b;

If you don't want to worry about the space in this statement, enclose the preincrement operator and the variable in parentheses:

sum = a+(++b);

Constants

There are two ways to define a constant in C++: with the #define preprocessor directive and with the reserved word const. Although both ways are valid, you're better off using the const reserved word since type-checking can be performed on such constants.

The syntax of the #define directive is:

#define identifier value

The syntax of the const reserved word is:

const data_type identifier = value;

Here's a simple example that shows how constants are declared using both the #define preprocessor directive and the reserved word const:

#include <iostream.h> #pragma hdrstop #define MAGIC_NUMBER 20 #define ANOTHER_NUMBER 101 const int MY_SECRET_NUMBER = 1000; const float SPEED = 2.66; #pragma argsused int main(int argc, char* argv[]) { return 0; }

Constants declared using the #define preprocessor directive aren't real constants because the C++ preprocessor replaces the defined identifier with the defined value (for instance, the MAGIC_NUMBER with 20) in the source code and then provides the C++ compiler with the modified source file. The object file generated by the C++ compiler actually doesn't contain a single reference to the MAGIC_NUMBER identifier or any other defined identifier.

Standard C++ Input with cin

The cin object, declared in the iostream.h header file just like the cout object, makes basic input in C++ as simple as it is in Delphi. To get input from the user using the cin object, you need to use the extraction operator (>>, two greater-than characters). Here's how you use the cin object to store user input to a variable:

cin >> variable;

Finally, here's the C++ version of the application that calculates the total cost of a product (the Delphi version of this example is displayed in Listing 2-16).

Listing 2-27: Working with user data

include <iostream.h> #include <conio.h> #pragma hdrstop const double SHIPPING = 1.15; #pragma argsused int main(int argc, char* argv[]) { double price; cout << "Product price: "; cin >> price; cout << "Price with shipping: $" << price * SHIPPING << endl; getch(); return 0; }

Категории