A C++ Crash Course Part II UW Association for Computing Machinery [email protected] Questions &...
-
Upload
kathryn-palmerton -
Category
Documents
-
view
216 -
download
2
Transcript of A C++ Crash Course Part II UW Association for Computing Machinery [email protected] Questions &...
A C++ Crash CoursePart II
UW Association for Computing Machinery
http://www.cs.washington.edu/orgs/acm/tutorials
Questions & Feedback to Albert J. Wong (awong)
What We Will Cover• C Preprocessor
– #include, #define, #if, etc.– __FILE__, __LINE__
• Multiple File Development– Header Files– Separate Compilation
• Compilation Process– Compilation– Linking
• Advanced Modifiers– const, static, extern,
volatile
• Namespaces
• Operator Overloading
• Classes– Constructors, Destructors– Inheritance– Virtual (dynamic dispatch)
• Dynamic Memory– new, delete, delete[]– malloc, calloc, realloc, free
• C/C++ I/O Functions
What We Are NOT Covering• Anything in the first tutorial
– Pointers, arrays, references– structs, unions, enums
• Weird Inheritance– Multiple inheritance– Virtual inheritance (NOT dynamic dispatch)
• Templates– Generic Programming
• Exceptions• STL• Makefiles
Basics refresher Quiz• Write a struct called Point3D that represents a 3D point.
Give it 3 member variables, x, y, z with type double.• Given that struct definition, and following code:
– Count how many times a Point3D is created– List all places memory is allocated, and the type of memory
allocated
typedef struct Point3D Point3D;Point3D add(Point3D *a, Point3D *b) {
Point3D p;p.x = a->x + b->x;p.y = a->y + b->y;return p
}
int main(void) {Point3D p1 = {0,1};Point3D p2 = {3,4};Point3D p3 = add(&p1, &p2);return 0;
}
Declarations - (bad) Example
int main(void) {int result;...
result = add(20, 3);
...return 0;
}
int add(int a, int b) {return a + b;
}
What is wrong with the following code? Will it compile in C? in C++?
Hint: It has to do with the declaration and use of add.
Declaration Regions
int main(void) {int result;int add(int,int);...
result = add(20, 3);
...return 0;
}
int add(int a, int b) {return a + b;
}...
int add(int,int);
int main(void) {int result;...
result = add(20, 3);
...return 0;
}
int add(int a, int b) {return a + b;
}...
add is declared in the shaded
regions
Corrected Code 1 (local prototype)
Corrected Code 2 (global prototype)
Declarations and definitions are separate concepts
Declarations - Summary
• Declarations can be separate from definitions• Function declarations are called prototypes• Declarations should be given before usage
• C & C++ handle undeclared functions differently– In C++ this is an error– In C, the function is implicitly declared with the type:int name(...);
Dangerous!
C-style IO is an acquired taste. Learn to like it.
I/O C-style
Basic functions:• printf, scanf, fprintf, fscanf, sprintf, sscanf, etc.• gets, puts, getc, putc, getchar• read, write, fread, fwrite
We will cover the basics of the “formated” family of functions (printf, scanf, etc).
For the others, read the man pages in Unix.
printf(char *format_string, ...);fprintf(FILE*, char *format_string, ...);
snprintf(char* buf, size_t n, char *format_string, ...);
printf
• In C, all devices are treated like files• Three standard files are:
– stdin Often the keyboard– stdout Often the text console– stderr Often the text console
• printf(....) is fprintf(stdout, ....)• The format string is a pattern for the output; it describes how to
display the arguments to printf.• Snprintf write to the string “buf”. The variable n specifies the size of
the buffer.• printf returns the number of characters written
format string
• Format strings are normal strings with embedded “conversion specifications” which are placeholders for arguments
• Conversion specifications are a ‘%’ and a letter with an optional set of arguments in between the ‘%’ and letter.
• To print a ‘%’, you need to write ‘%%’
Example:printf(“Here is a number: %d\n”, 10);
%d is the conversion specification for signed integers.
Conversion Specifications
Conversion Specifications:• %d, %i -- signed integer• %u -- unsigned integer• %f -- floating point number• %c -- character• %s -- string• %x -- hexadecimal value• %p -- pointer
Converion specifications tell how to translate a data value into a string
Options:• l -- long (32-bit value)• ll -- long long (64-bit value)• n -- field width of n digits• .n -- precision of n digits• 0 -- fill unused field with 0s
There are many more! Read man pages, or Google it.
printf quiz!
Figure out the output of the following:
• printf(“%.3f rounded to 2 decimals is %.2f\n”, 2.325, 2.325);
• printf(“%d in hex is: %04x\n”, 24, 24);
• printf(“Quizzes are fun, ja?\n”);
scanf(char *format_string, ...);
fscanf(FILE*, char *format_string, ...);
sscanf(char*, char *format_string, ...);
scanf
• scanf(....) is fscanf(stdin, ....)• All arguments ot scanf must be pointers (or arrays)• scanf does almost no size checks. It is easy to get a
buffer overflow here. Make sure you use a field length specifier with the %s conversion specifer!!!
• scanf returns the number of items read.
scanf Examplesint items_read;
Read a number:int num;items_read = scanf(“%d”, &num);
Read a character:char ch;items_read = scanf(“%c”, &ch);
Read a string of max length, 79 chars:char buf[80];buf[79]=‘\0’; // Ensure a terminating NULL.items_read = scanf(“%79s”, buf);
Read number after pattern of “a:<num>”:int num;items_read = scanf(“a:%d”, &num);
always check the return value of
scanf
C++-style IO is easier for simple stuff
I/O C++-style
Basic classes:• iostream (cout, cin, cerr)• ostringstream, istringstream
cout << “Hello World!” << endll;cout << “Boo! “ << 10 << ‘c’ << endl;cerr << “Here’s the error stream” << endl;
int n;cin >> n;
char ch;cin >> ch;
...but harder for complex stuff
I/O C++-style continued...
printf(“%.3f rounded to 2 decimals is %.2f\n”, 2.325, 2.325);
…becomes…
cout << setprecision(3) << 2.325 << “ rounded to 2 decimals is “<< setprecision(2) << 2.3.25<< endl;
C and C++ I/O comparedC-style I/O:
• No type safety. What happens with printf(“%d”, ‘c’);?• Conversion specifications have a high learning curve.• Almost all the state of the I/O is contained in the function call.
C++ style I/O:
• Manipulators are very verbose/annoying
• Global state gets changed. When you do “cout << 2.4555”, what precision are you set at? You don’t know. It’s worse with threads.
• You get more customizability since C++ I/O is classed based.
NEVER mix C and C++ I/O...until you know what ios::sync_with_stdio() does.
Multiple File DevelopmentRelated functions and variables can be
grouped into different files
• Each file is considered a “module”• There is no enforced relation between the
filename and its contents!
int add(int a, int b);
int main(void) {int result;printf(“%d\n”, add(a,b));return 0;
}
int add(int a, int b) {return a + b;
}
int sub(int a, int b) {return a - b;
}
main.cc utils.cc
The compilation Process
Preprocessor
.c .h .c .h
Compiler
Linker
executable
Libraries
Source code (text)
C/C++ code (text)
Object code (bin)
Native Executable (bin)
PreprocesserResolves #define, #include
CompilerTranslates code to Machine Language. It outputs an “object file.” This code is not executable
LinkerTakes object files and resolves references to functions and variables in different files
Compilation in Unix
The following commands perform the whole compilation process for C and C++:gcc -Wall -g file1.c file2.c -o prognameg++ -Wall -g file1.cc file2.cc -o progname
You can control which stages get run:• Only run the preprocessorgcc -E file.c
• Only run the compiler (don’t link)gcc -Wall -ansi -c file.c
• Link these filesgcc file1.o file2.o -o progname
Common Compilation options• -Wall enable all warnings• -ansi turn on strict ansi compliance• -v verbose mode on. (lists which directories were searched for
include files and libraries)• -g generate debugging symbols• -c compile only (create object file)• -E run the preprocessor only• -s generate assembly code (instead of object code)• -I<dir> prepend directory to include path• -L<dir> prepend directory to library path• -l<libraryname> library to link (looks for lib<libraryname>.so, or
.a, or .la) in library path• -o <filename> specifies output filename• -O[n] specifies optimization level (default 0)• -D<name>[=value] define the give preprocessor Tag
Always specify -Wall and -g: gcc -Wall -g <filenames...>
Preprocessor and Compiler
Preprocessor– Does not understand C/C++– Produces text that gets read by the compiler
Compiler– Expects pure C/C++ (no preprocessor stuff)– Checks syntax– Typechecks your code– Generates, and optimizes, machine code– Produces object files for the linker– Still knows what source file and line numbers
LinkerLinker
– Resolves dependencies between object files – Places functions, variables, in final location– Generates executables– Does no code optimization– Knows nothing about source files (filenames or line
numbers)– Knows nothing about “types”– Matches dependencies by name alone– In C++, linker symbols have been mangled by the
compiler (name mangling) to include the return type and argument types. This allows for overloading.
– Name mangling is compiler dependent. The linker may not be able to link objects from different compilers.
Object Files
• Object files contain compiled code plus an index stating what symbols it has, and what symbols it needs
• Use nm (unix) and dumpbin (windows) to list the index
• The linker look at all the the object files and tries to find a one-to-one mapping of “needs symbol” to a “has symbol”
• .dll and .so files (windows and unix respectively) are object files with special indexes that the OS can understand and use at runtime.
• Object File extensions: .o, .obj
Identify who gave the errorError 1:test.c:1:10: #include expects "FILENAME" or <FILENAME>
Error 2:/tmp/ccdoe7a7.o: In function `main':/tmp/ccdoe7a7.o(.text+0x7): undefined reference to `foo'collect2: ld returned 1 exit status
Error 3:test.c: In function `main':test.c:4: `iii' undeclared (first use in this function)test.c:4: (Each undeclared identifier is reported only oncetest.c:4: for each function it appears in.)test.c:4: parse error before `989'
Error 4:/tmp/ccwltu5R.o: In function `foo':/tmp/ccwltu5R.o(.text+0x0): multiple definition of `foo'/tmp/ccx3bPfI.o(.text+0x0): first defined herecollect2: ld returned 1 exit status
Break
• Stand up
• Stretch
• Play with stuff animals
• Next topics:– Header Files
– Preprocessor
Header FilesCommon Usages:• Creates an informal module interface (No relation to
Java interfaces)• Provides documentation• Each module usually has a header file• Often include the following:
– function prototypes– struct and class declarations– typedefs– global variable declarations– Lots of (high-level) comments
• Abstracts code for optimization (less common)
Header File Example (has error)point2d.h
struct Point2D { int x; int y; };typedef struct Point2D Point2D;
/* returns the result of the vector addition of * a and b. */Point2D add(Point2D *a, Point2D *b);
/* returns the result of the vector subtraction of * b from a */Point2D sub(Point2D *a, Point2D *b);
There is a subtle problem with this header file. It is shown on the next slide.
Header File Problemoutput.h
#include “point2d.h”#include “point3d.h”
/* pretty print the different point types to * stdout. */void Point2D_prettyPrint(Point2D *p);void Point3D_prettyPrint(Point3D *p);
main.h#include “point2d.h”#include “output.h”int main(void) {
Point2D p;p.x = 3; p.y = 5;Point2D_prettyPrint(&p);return 0;
}
We get a compile error. Multiple definition of struct Point2D
We use the preprocessor to fix this
Preprocessor OverviewThe preprocessor is a lexical macro engine
run before the compiler sees the code
• Performs lexical transforms of text– It does not understand C/C++– There is no concept of types
• Transforms are based on lexical substitution– Think Search and Replace
• Preprocess directives (commands) start with ‘#’– Each directive goes on its own line– The # must be the first character on a line.
• No semicolons!!!!!!!!!!!!– Newlines end a preprocessor directive, no a ‘;’.
#define • #define Tag Substitution
– Replaces all following occurrences of Tag with Substitution– The Substitution may be the empty string– Does not replace Tag if it is inside quotation marks
• #define Tag(x,y,z) Substitution– Creates a Function-like macro Tag– The Substitution may refer to the parameters x, y, or z– Only items of the form Tag(x,y,z) will be replaced (Just plain Tag will be ignored)
#define MAX_SIZE 80#define GET_FIELD(a,b) a->b
int ar[MAX_SIZE];GET_FIELD(point, xCoord);GET_FIELD(“lalala", f03j?);
int ar[80];point->xCoord “lalala”->f03j?
The #if, and its variants• #if constant-expression
Include the following block of text if constant-expression is non-zero
• #ifdef TagInclude the following block if Tag is currently defined (via an earlier #define)
• #ifndef TagInclude the following block if Tag is currently not defined (via an earlier #define)
#else, #elif, #endif
• #elseUsed to delimit the else clause in a preprocessor if statement
• #elif constant-expressionUsed to create an else-if clause in a preprocessor if statement
• #endifDelimits the end of a preprocessor if statement. There should be exactly one of these for each #if, #ifdef, and #ifndef.
#if examples
#ifdef INCLUDE_DEBUG_PRINT# define DPRINT(msg) \
fprintf(stderr, “DBG: %s”, msg);#else# define DPRINT(msg)#endif
#ifdef WIN32# define open _open# define close _close#endif
The DPRINT macro when INCLUDE_DEBUG_PRINT is defined, evaluates to printing code. Otherwise, it evaluates to the empty string.
Windows calls the open and close functions, _open, and _close respectively. This is annoying, so let’s fix it with preprocessor macros.
#include#include essentially copies and pastes the given
file into the current line
• There are two forms of #include• They differ in the order in which directories are search
for the given file• The search order is implementation defined• Here is the general pattern for different compilers:
#include <filename>• Searches the “include path,” then the current directory
#include “filename”• Searches the current directory, then the “include path”
#undef, #error, #warning• #undef Tag
Removes definition of a Tag. (undoes a #define)
• #error messageCauses compilation to stop at this line with the given error message. Often this is used with #if blocks to indicate an invalid set of #define macros.
• #warning messageCauses the compiler to output an warning at this line with the given message. Can be used as strong reminders that a file needs work.
• #pragma optionUsed to pass an option to the compiler. Almost all #pragma commands are compiler-dependent.
#pragma, #line• #pragma option
Used to pass an option to the compiler. Almost all #pragma commands are compiler-dependent.
• #line numberUsed to change what line number that the compiler thinks it is on.
This is often seen in:• Computer Generated Code (from like flex, bison, or something)• Code outputed by the preprocessor
#line to allows programs to make the compiler’s error messages to correspond to the original source file’s line numbers rather than the generated source file’s line numbers.
Useful MacrosThere are a few macros (#defines) that are given by the
compiler that are very useful to know when trying to debug code.
• __FILE__ string literal of the current filename
• __LINE__ integer literal with the current line number
• __func__ string literal of the current function name
• __DATE__ string literal of the current date
Other Weird (But Useful) Notes• If you need to break anything into multiple lines, end the line with a
single ‘\’. The lexer (thing that reads the file) will concatinate the two lines for you. Avoid doing this unless you have no other choice.
• Multiple string literals in a row, with only whitespace separating them, are automatically concatinated.
“Hi” “Mom! “ “Here’s a String!”“HiMom! Here’s a String!”
• In #define macros, you can get a quoted version of the input argument by prepending the argument with a #.#define mk_str(x) #x used as mk_str(hi) yields “hi”
• In #define macros, you can concatinate input arguments with ##.#define foo(a) a##foo used as foo(hi_) yields hi_foo
#define DBG_MKSTR(a) #a#define DBG_LOCATION_0(x) __FILE__ "," DBG_MKSTR(x) " -- "
#define DBG_LOCATION DBG_LOCATION_0(__LINE__)#define LOCATION_STR(x) DBG_LOCATION x
#if !NDEBUG# define LOG(level, msg, args...) \ if (g_debugLevel >= (level)) \ fprintf(stderr, \
#level ": " DBG_LOCATION msg, ##args)#else# define LOG(level, msg, args...)#endif
#define INFO 0#define WARNING 1#define ERROR 2
Complex Example
Usage: LOG(INFO, “Program got here\n”);
Complex Example Exercise
LOG(INFO, “Program got here\n”);
What is the output of the following line assuming NDEBUG is not defined? What is if it is definied?
Assume the following:• The filename is test.cc• The line number is 123
Preprocessor Summary• The preprocessor does lexical manipulations
• Preprocessor commands do not end in semicolons
• All preprocessor commands start with a ‘#’
• The most common (important) preprocessor directives are: #include, #define,and #ifndef
• Useful directives that are not used enough are: #error, and #warning.
• There are a number of provided macros that are very useful to know. In particular, know about __FILE__, __LINE__, __func__
(dup) Header File w/ subtle errorpoint2d.h
struct Point2D { int x; int y; };typedef struct Point2D Point2D;
/* returns the result of the vector addition of * a and b. */Point2D add(Point2D *a, Point2D *b);
/* returns the result of the vector subtraction of * b from a */Point2D sub(Point2D *a, Point2D *b);
There is a subtle problem with this header file. It is shown on the next slide.
(dup) Header File Problemoutput.h
#include “point2d.h”#include “point3d.h”
/* pretty print the different point types to * stdout. */void Point2D_prettyPrint(Point2D *p);void Point3D_prettyPrint(Point3D *p);
main.h#include “point2d.h”#include “output.h”int main(void) {
Point2D p;p.x = 3; p.y = 5;Point2D_prettyPrint(&p);return 0;
}
We get a compile error. Multiple definition of struct Point2D
We use the preprocessor to fix this
Header Guards
Wrap each header file with the lines:
#ifndef FILENAME_H
#define FILENAME_H
<header file body here>
#endif /* FILENAME_H */
Header Guards are a common C/C++ idiom
There is almost no reason to put things outside of header guards
Header File (corrected)point2d.h
#ifndef POINT2D_H#define POINT2D_H
struct Point2D { int x; int y; };typedef struct Point2D Point2D;
/* returns the result of the vector addition of * a and b. */Point2D add(Point2D *a, Point2D *b);
/* returns the result of the vector subtraction of * b from a */Point2D sub(Point2D *a, Point2D *b);
#endif /* POINT2D_H */
Header File Problem (fixed)output.h
#ifndef OUTPUT_H#define OUTPUT_H
#include “point2d.h”#include “point3d.h”
/* pretty print the different point types to * stdout. */void Point2D_prettyPrint(Point2D *p);void Point3D_prettyPrint(Point3D *p);#endif /* OUTPUT_H */
#include “point2d.h”#include “output.h”int main(void) {
Point2D p;p.x = 3; p.y = 5;Point2D_prettyPrint(&p);return 0;
}
Error fixed since on the second #include of point2d.h, POINT2D_H
has been defined and thus, its contents are skipped
main.h
The header guard for output.h never gets used, but you should still have it
just incase.
Intermission
• Stretch
• Go use the restroom
• We restart in about 5 minutes
• Next topics:– Variables (globals, advanced modifiers)– Classes– Dynamic Memory
Dynamic Memory
• Dynamically sized memory in C and C++ must be manually managed
• Dynamic memory is not necessarily much slower than static memory
• All allocated memory must be freed by the user• Do not free memory twice (double free).• Do not free memory that was allocated by you• Manual memory management allows for finer
grained control of your program• It’s not that scary, nor that hard.
new, delete, delete[]
• the new operator allocates new memory, initializes it and returns a pointer to it.
• the delete operator deallocates memory allocated by new
• If you allocate a new array, you must delete it with delete[] and not delete
Improper use of delete and delete[] will cause undefined behavior!
Point2D *p = new Point;delete p;p = NULL;
int *ar = new int[50];delete[] ar;ar = NULL;
Example:
malloc, calloc, realloc, free• These are C memory management functions• Do not mix them with the C++ ones! (that is, don’t
try to delete memory from malloc, etc.)• These functions return void* (pointers to anything)• They are not typesafe• They do not call initializers for the memory• There is no realloc equivalent for C++• Some low-level memory management may be
faster with these functions, but don’t bank on that.
Global Variables• Global Variables are not evil!
• Allocated at program start.
• Deallocated at program end.
• By default, initialized to bit-wise zero (do not depend on this).
• Need to understand modifiers: extern, static, and const to use properly.
• Need to understand linking to use properly.
Global Variables - Gotcha I
/* util.c */
int g_numCalls = 0;
void someFunc(void) {fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls);...
}
What is wrong with this code?
/* test.c */void someFunc(void);int g_numCalls = 0;
int main(void) {fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls);
someFunc(); someFunc();...
}
compile line: gcc -Wall -ansi util.c test.c -o test
static
On a global variable or a functionstatic int g_someGlobalVariable;static void myFunction(void);Tells the linker not to export the variable or function. Essentially makes the identifier “file scope,” as the linker will not use it fulfill dependencies from other files.
On a local (function) variablevoid someFunc(void) {
static int array[4000];}Places the variable off the stack. This has the side-effect that it retains it value across calls. It is often used when a variable is too large to be put on the stack.
On a class member (covered when we discuss classes)
static has 3 very separate meanings
Globals Variables - Gotcha I (fixed)
/* util.c */
static int g_numCalls = 0;
void someFunc(void) {fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls);...
}
Static to the rescue!!!!!
/* test.c */void someFunc(void);static int g_numCalls = 0;
int main(void) {fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls);
someFunc(); someFunc();...
}
compile line: gcc -Wall -ansi util.c test.c -o test
The two variables “g_numCalls” have no relation. Think of them as private to each file.
Global Variables - Gotcha II
/* debug.h */
int debug_level;
…
What is wrong with this code?
/* test.c */
#include “debug.h”…
compile line: gcc -Wall -ansi *.c -o test
/* debug.c */
#include “debug.h”…
/* otherfile.c */
#include “debug.h”…
Global Variables - Gotcha II (bad fix)
/* debug.h */
static int debug_level;
…
/* test.c */
#include “debug.h”…
compile line: gcc -Wall -ansi *.c -o test
/* debug.c */
#include “debug.h”…
/* otherfile.c */
#include “debug.h”…
…but get 3 distinct copies of debug_level! bad!
static with fix the compile error…
extern• The problem is:
– you want to declare int debug_level– you don’t want to allocate space for it every time
• This is exactly what extern does.• extern int debug_level;• This means, “there exists an int called debug_level, but
the storage is not here. Go find it linker! Go!”
• Function Prototypes are implicitly declared as extern!• As with prototypes, you must remember to actually
declare the real variable somewhere (preferable in one implementation file ).
Global Variables - Gotcha II (good fix)
/* debug.h */
extern int debug_level;
…
/* test.c */
#include “debug.h”…
compile line: gcc -Wall -ansi *.c -o test
/* debug.c */
#include “debug.h”
int debug_level;…
/* otherfile.c */
#include “debug.h”…
Remember, you have to create the variable somewhere, hence the int debug_level in debug.c
Ahh….All better.
const
• Unlike other globals, constant variables can be declared and allocated in the headers without problems.
• All const variables must be initialized at declaration.• const is a compile-time feature; it is part of the type.• const is mainly useful in association with references
and pointers as parameters to functions.• Since it is part of the type, you can cast it away • Casting it away is a bad idea if the actual instance was
initially created as const.• Use const as often as possible!
const int var = 0;void prettyPrintPoint(const Point2D &p);void prettyPrintPoint(const Point2D *p);
const Syntax oddities
• This means the ordering of const and * matter.• Read modifiers from right to left.
int * const p = &n; // constant pointer to an integer.
The pointer, p, is constant, but the integer it points to is not.
const is a type modifier (like * and &)
int n;const int *p1 = &n;int const *p2 = &n;int * const p3 = &n;int *p4 = &n;
p1 = p2; // ok. p1 and p2 have the same type.*p2 = 1; // Error. p2 is a pointer to a constant;p3 = p2; // Error. p3 is a constant pointerp4 = p2; // Error. p4 doesn’t guarantee *p4 is constp1 = p3; // ok. p1 is a stronger restriction than p3
namespaceNamespaces group functions and
variables under a prefix• Analogous to Java Packages (w/o access modification,
or path restrictions)• Used to avoid name collisions.• Declared by:
namespace <name> {}
• All symbols (functions and variables) are under the prefix <name>.
• Symbols accessed by <name>::symbol• Namespaces can be nested.• You can omit the <name>:: when referring symbols from
the same namespace, or a containing namespace.
usingusing directives influence the symbol
lookup for namespaces• Analogous to Java import statements• There are 2 forms:
– using <name>::symbol;– using namespace <name>;
• The first form tells the compiler that symbol means <name>::symbol.
• The second form tells the compiler to look for <name>::symbol if it cannot find symbol in the current namespace.
• NEVER put using directives in header files!!! Bad Form!!• All standard library symbols are in the namespace std
Namespace example#include <iostream>
namespace Albert {void greet() { std::cout << “Hi from Albert!”; }
}
namespace Piyo {void greet() { std::cout << “Peep from Piyo!”; }void squeak() { std::cout << “squeak! Squeak!”; }
}
Albert:: greet(); // Hi from Albert!greet(); // Compile error. No symbol “greet”
using Piyo::greet;greet(); // Peep From Piyo!Albert::greet(); // Hi From Albert!squeak(); // Compile error. No symbol “squeak”
using namespace Piyo;greet(); // Peep From Piyo!Albert::greet(); // Hi From Albert!squeak(); // squeak! squeak!
Operator Overloading
• In C++, you can define operators (+,-,*,/, etc.) for new types.
• Operators are usually binary, or unary functions.• Examples of unary operators:!false, -i
• Examples of binary operatorsa + b, isBig || isRed
• The syntax for referring to the operator function is operator<symbol>
• Here is the prototype for integer addition (+):int operator+(int lhs, int rhs);
Operator Overloading Example
Point2Doperator+(const Point2d &lhs, const Point2d &rhs) {
Point2D p;p.x = lhs.x + rhs.x;p.y = lhs.y + rhs.y;
return p;}
What happens if I have the following prototype?Point2D operator+(Point2d lhs, Point2d rhs);
How about this one?Point2D operator+(Point2d &lhs, Point2d &rhs);
Discussion Point
What are the benefits of operator overloading? What are the drawbacks?
Bonus Question: Are they necessary for C++?
Classes• Roots come from C-style structs• Fairly similar to Java classes in concept.• Used to group related data and functions.• Can be used to write OO code
class Queue {public:
Queue();void enqueue(int n);int dequeue();~Queue();
private:int numElements;int capacity;int *queueData;
};
Basic class Syntax
Declaring a class: class [optional name] {
[access modifier]<type> member1;<type> member2;
[access modifier]<type> member3;<type> member4;…
} [instance list];
Example: class Point2D{
private:int x;int y;
public:Point2D(int x, int
y);int getX();int getY();
} p1(2,3);
Point2D p2(1,3);Point2D *p;
Declaring a class without inheritance
/* point2d.h */
#ifndef POINT2D_H#define POINT2D_H
class Point2D{private:
int x;int y;
public:Point2D(int x, int
y);int getX();int getY();
};
#endif /* POINT2D_H */
Declaring & Defining methods/* point2d.cc */
#include “point2d.h”
Point2D::Point2D(int x, int y){x = 0; y = 0;
}
int Point2D::getX(){return x;
}
int Point2D::getY(){return y;
}
Classes form a closed namespace
Constructors
• Constructors have the same name as their class• Constructors may not pass off control to another
constructor• A default (zero argument) constructor is
provided when no other constructors declared• Constructors may invoke the constructors of
their super class, and of their member variables via member-wise initialization.
Constructors are functions that get called when a class is instantiated
Memberwise InitializationMemberwise Initialization changes what constructor
gets called for members and parent classes
Standard way:Point2D::Point2D(int x, int y){ x = 0; y = 0; }
Memberwise Initialization (more C++) way:Point2D::Point2D(int x, int y): x(0), y(0){}
• The order matter. The order must match the order the variables are declared.
• To call a member variables constructor, specify the name of the variable, and then the arguments to the constructor
• To call a different parent class constructor, specify ParentClassName(args)
DestructorsDestructors are called when a class is deallocated
• Destructors are have no return type and have the same name as their class with a ‘~’ prepended.
• If no destructor is given, a trivial destructor, which calls the destructor for all elements is given.
InheritanceInheritance is specified by a : and a list of access specifiers + class names in the class declaration
class Point2D{private:
int x;int y;
public:Point2D(int x, int
y);int getX();int getY();
};
class ColorPoint2D : public Point2D
{private:
int color;
public:ColorPoint2D(int
x, int y, int
color);int getColor();
};
Inheritance continued
• Base classes can be public, protected, or private– In public inheritance, all public and protected
members are inherited– In protected inheritance, all public members from the
base class become protected– In private inheritance, all public and protected
members become private
• Java only has public inheritance• You can call any ancestor’s class method using
the scope resolution operator (::)
Dynamic Dispatch
• By default, dynamic dispatch is not enabled in C++!!• For a function to have dynamic dispatch, it must be
declared “virtual”.• If it is not declared virtual, then the static type when the
function is called, (that is, the type of the pointer, or reference) is used to resolve the function.
• If you ever use any dynamic memory with a class, MAKE ITS DESTRUCTOR VIRTUAL!
• In general, it is safe to make all your functions virtual.• Once a function is made virtual in a hierarchy, it cannot
be made “non-virtual” later in the hierarchy.
Abstract Classes
Cannonical Form
Const
Weirdnesses
• static members
friends
• Classes and functions can be declared as friends by writing– friend <classname>;– friend <function prototype>;
• Friends have access to a class’s private members.
Remember, only friends can touch each other’s private parts