Lesson 3
Overloading
Shit you should know
void foo(int i)
void foo(int &i)
void foo(int &i)
These two are ambiguous since both functions can be used.
void foo(int i)
void foo(int i, int j=10)
void foo(int i, int j=10)
Ambiguous, as well.
Overload Resolution
Promotion: (no loss of precision)
Any integral type (char, short, bool, long) -> int
float-> double
Standard: (loss of precision)
Any legal conversion between built-in types (POD) that is not an exact match or promotion.
Examples:
char -> bool
char -> long
float -> int
int -> float
char -> long
float -> int
int -> float
User: (user defined)
conversion performed by a user-defined constructor or user-defined conversion operator.
Exact > Promotion
If exact + promotion and promotion + standard, first wins.
If standard + exact and standard + standard, first wins again.
So far, these are pretty easy.
Here's the most important rule, from the prof's mouth:
For a function to be better, it has to be no worse in all parameters and strictly better in at least one.
standard + exact and exact + standard is ambiguous.
Combination (strings) of Conversions
For IMPLICIT CONVERSIONS:
System-defined conversions and user-defined conversions can be used, even combined (float -> int -> D) but only ONE user-defined conversion can be in a combination (float -> int -> D -> C is NOT allowed). But remember, this is for IMPLICIT.
For EXPLICIT CONVERSIONS:
Everything goes.
Const Conversions
void foo (int &)
void foo (int const &)
void foo (int const &)
This is legal. The rule for this is very simple:
If const and non-const are legal, then match the types. non-const types will use the non-const function, const will use the const function.
Some tangents on various shit
void as function parameter
void foo(void);
That is the correct way to say "no parameters" in C, and it also works in C++.
But:
void foo();
Means different things in C and C++! In C it means "could take any number of parameters of unknown types", and in C++ it means the same as foo(void).
Variable argument list functions are inherently un-typesafe and should be avoided where possible.
But, I mean, we're mostly using C++. Just keep this at the back of your head, but don't worry too much about it.
Member Initializer Lists in relation to Efficiency
You normally don't have member initializer lists to save on efficiency, but again, just a note.
If you're not using an MIL for a user defined type, the compiler will fill the variable with garbage before it is assigned within the constructor. This should be obvious to you - but it's easy to forget.
This can be proved by trying to initialize a const value in the constructor instead of in an MIL - of course, the compiler will choke and die.
Just use Member Initializer Lists whenever possible. It's good shit.
Member Initializer Lists
Remember that the compiler will go through the MIL not in the order you put it, but in the order of the variable initialization in the class.
class C {
public:
C(): j(0),i(j) { }
private:
int i;
int j;
}
public:
C(): j(0),i(j) { }
private:
int i;
int j;
}
What do you think is in i? 0? Cause if you do, that's what you'll get for the question when it comes out in the exam.
i is filled with a GARBAGE VALUE.
I
nfinite copy constructors
C (C original) is not legal. That's some infinite Inception bullshit.
const refs
const & is the same as & const. Volper thinks const& is more correct, though. Which I agree with. Yeah, that's all I got.
Default Constructor automatic generation rules
Default constructor will not be automatically generated if any other constructor is defined in the class.
Default Member Initializers
C++03 only allows initialization in the class for static consts.
private:
static const int classID = 3;
static const int classID = 3;
C++11 allows initialization like this - they are alled default member initializers. Remember the name - it is a useful mnemonic for memorization.
class C {
public:
//some shit
private:
int i = 3; //ok
int const j = 5; //ok
int a[3] = {1,2,3} //ok
int a[] = {1,2,3} //legal code inside function body (even in C++03, illegal in class declaration)
static const int classID = 3;
//static int QID = 5; still not legal
}
int C::QID = 3; //initialization of static non const must be outside of class declaration.
public:
//some shit
private:
int i = 3; //ok
int const j = 5; //ok
int a[3] = {1,2,3} //ok
int a[] = {1,2,3} //legal code inside function body (even in C++03, illegal in class declaration)
static const int classID = 3;
//static int QID = 5; still not legal
}
int C::QID = 3; //initialization of static non const must be outside of class declaration.
Brace/List Initialization
It is strongly recommended to use brace initialization (Prof Volper's terminology, it is referred to online as list initialization), which will catch if initialization requires narrowing - conversion that loses precision.
From Stroustrup's tome on C++:
List initialization does not allow narrowing (§iso.8.5.4). That is:
• An integer cannot be converted to another integer that cannot hold its value. For example, charto int is allowed, but not int to char.
• A floating-point value cannot be converted to another floating-point type that cannot hold itsvalue. For example, float to double is allowed, but not double to float.
• A floating-point value cannot be converted to an integer type.
• An integer value cannot be converted to a floating-point type.
It can be used either int i = {3} or int i {3};
Example:
void fun(double val, int val2) {
int x2 = val; // if val==7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2==1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
int x2 = val; // if val==7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2==1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
Exception: The only situation where = is preferred over {} is when using auto keyword to get the type determined by the initializer.
Example:
auto z1 {99}; // z1 is an initializer_list<int>
auto z2 = 99; // z2 is an int
auto z2 = 99; // z2 is an int