c++ features and constructs ch. 3 except 3.2, 3.4, 3.9, 3.11
TRANSCRIPT
Scope
• Programs are built of nested "scopes".– Sometimes called "scope blocks" or "name
spaces"
• Inner scopes "hide" or "shadow" outer scopes.
• Variables are only accessible when they are "in scope".
Kinds of scope
• Three main kinds of scope in C++– Local: function or block– Class: extent of the class– File: only available within a file
• Also – Function scope: labels and gotos– Global scope
Scope Exampleslong x;
float y;
int z;
void fn(char c, int x) { // parameter hides global x
extern int z; // refer to global z
double y = 3.14; // shadows global y
{
char y; // shadows double y from above
y = c; // assigns to inner y
::y = 0.3; // assign to global y
}
y = y/3.0; // assign to local y
z++; // increment global z
}
Class Scope
• Class members and methods are available anywhere in the class without forward declaration (a.k.a. prototype)
• Examples:Vector::Vector(int x, int y) {
Vector::x = x;
Vector::y = y;
}
New Topic: Optional Arguments
• Arguments to a function can be given default values.
• Example:int echo(int value=0) {
return value;
}
echo(10); // returns 10
echo(); // returns 0
Optional Arguments (cont’d)
• Optional arguments must be at the end of the argument list
• When might this be useful?
New Topic: Overloading Functions
• Functions have signatures– A function's signature is
• the function's name
• its parameter list (types and orders)
• C++ allows functions with different signatures to have different definitions.
Overloading Functions
• Examples:
int power(int a, int n);
int power(double a, int n);
• What's a problem here?
Function Call Resolution:
1. If there's an exact match, call that version
2. Match through standard type promotions
3. Match through standard conversions
4. Match through user supplied conversions (section 8.7)
5. No match (error)
C++ is Strongly Typed.
• C++ is strongly typed– All variables must have a type before being
used.
• Types must match before function calls can be allowed
Standard Promotions
• Promotions take types and increase their resolution
• Examples:– short to int– int to long– ...
Standard conversions
• Conversions convert a variable to a different type
• Examples:– int to float– float to int– ...
C++ is Strongly Typed
• Types still need to match – Consider two functions like:
int operator +(int lhs, int rhs);
float operator +(float lhs, float rhs);
– One of these must match for a = x + y;
When Does Conversion Happen?
• When does the compiler do this? – Arithmetic– Function calls (argument type conversion)– Return values
Explicit Type Conversion (Type Casting)
• In C++, casts look like:
<type-name>( <expression> )
int x = int(3.14);
New Topic: More About References
• References can be variables as well as parameters to functions
• They must be initialized when declared
• Example:– int a;– int &ra = a; // ra is a reference to a
References (cont’d)
• A reference must be initialized to an "lvalue" – an lvalue is anything that can appear on the left-
hand side of an assignment statement
New Topic: Read-only Variables (const)
• Variables can be declared read-only
• Example:const <type name> <variable name> = <value>;
const int forever_one = 1;
• Read-only variables are initialized at declaration but cannot be changed at run-time.
Read-only Parameters (const)
• Parameters can be read-only too.
• Example:int foo(const int x) { ... }
• How does this come in handy?
New Topic: Dynamic Allocation in C++
• Use operator new in place of malloc()
<pointer variable> = malloc(<type>);
<pointer variable> = new <type>;
• new understands about class constructors!
Dynamic Allocation Examples
int * int_ptr = new int;
int * ten_ptr = new int(10);
int [] int_array = new int [10];
Vector * vptr = new Vector(5, 6); // calls vector constructor!
delete int_ptr;
delete ten_ptr;
delete [] int_prt;
delete vptr;
A Longer Example: Fractions
• Fractions are numbers of the form:
• numerator/denominator
• Fractions have several properties:– The numerator and denominator are both
integers.– The denominator cannot be 0– Arithmetic operations are well defined for
fractions.
Questions about Fractions
• How should a fraction be stored?– A pair of integers, numerator and denominator
• What operations should we support for fractions?– +, -, - (unary), etc.– <, >, ==– reduce(), print()
class Fraction {
public:
Fraction();
Fraction(int);
Fraction(int, int);
print();
Fraction operator +(Fraction);
Fraction operator -();
Fraction operator -(Fraction);
int operator <(Fraction);
int operator >(Fraction);
int operator ==(Fraction);
private:
int numerator, denominator;
};
Constructor Considerations
• What if denominator is zero?– Exit the program
• We have three cases:– no arguments (default to 0/1)– one argument (numerator)– two arguments (numerator and denominator)
• Anything else?
ConstructorsFraction::Fraction() {
numerator = 0;
denominator = 0;
}Fraction::Fraction(int num) {
numerator = num;
denominator = 1;
}
Fraction::Fraction(int num, int denom) {
numerator = num;
if (denom == 0)
exit(1);
denominator = denom;
}
print()
• Print() should print the fraction in the form numerator/denominator to stdout
void print() {
cout << numerator << “/” << denominator;
}
Fraction Fraction::operator +(Fraction right) {
Fraction answer;
int left_num, right_num;
left_num = right.denominator * numerator;
right_num = denominator * right.numerator;
answer.denominator = right.denominator * denominator;
answer.numerator = left_num + right_num;
return answer;
}
Fraction Fraction::operator -(Fraction right) {
Fraction answer;
int left_num, right_num;
left_num = right.denominator * numerator;
right_num = denominator * right.numerator;
answer.denominator = right.denominator * denominator;
answer.numerator = left_num - right_num;
return answer;
}
An Easier Way to Subtract Fractions
Fraction Fraction::operator -(Fraction right) {Fraction left = *this;
return (left + -right);
}
int Fraction::operator <(Fraction right) {
int left_int = numerator * right.denominator;
int right_int = right.numerator * denominator;
return (left_int < right_int);
}
int Fraction::operator >(Fraction right) {
int left_int = numerator * right.denominator;
int right_int = right.numerator * denominator;
return (left_int > right_int);
}