=
, ()
, and {}
int a = 4;
int a(4);
int a{4};
int a;
auto b = a;
decltype(c) b;
// all a, b, and c are int
wrap-around
for: // signed (wraps around to `-minimum_negative`)
for(short i=32765;i<32777;i++){ } //infinite loop; max is 32767 (2^15 - 1)
// unsigned (wraps around to `0`)
for(short int i = 65534; i < 65537; i++){ } //infinite loop; max is 65535 (2^16 - 1)
signed
unsigned
encounters are always trickysizeof(int) > -1 //false; as -1 is all 1's (very big number) in 2s complement form and it is converted to unsigned on comparison with sizeof(unsigned type)
unsigned a = 4;
cout << (a > -1); // false; same reason as above
short i = 32768; //i = -32768; as we are doing short = int here, int value in short container is -32768 (wrap-around)
R"this\n is a\t raw string"
string
object#include <string>
string str;
string str = ""; // same as above
str.length(); // 0
str.size(); // same as above
// pitfall; there is no index 0 in an empty string
str[0] = 'a'; // so this statement does nothing!
// append a char
str += 'b';
// append a string
str += "bc";
str.append("bc");
stringstream
: treating string as an I/O stream#include <sstream>
string name = 'Abhi';
string str;
stringstream(name) >> str;
stringstream(name) << str;
endl
vs "/n"
: endl flushes stream everytime it is encountered hence it’s slower
Both cin
and scanf()
leaves a "\n"
in the input buffer that can be read by a subsequent method like getchar()
.
Solution: use fflush(stdin)
(C) or cin.ignore()
(C++) just after cin
or scanf()
.
// for <streamsize>
#include<ios>
// for numeric_limits
#include<limits>
cin >> a;
// discards the input buffer
cin.ignore(numeric_limits<streamsize>::max(),'\n');
while (cin >> input)
: cin
returns false when a non-numeric value is entered; this trick applicable to int
/numeric types only
Strings: C-style
or using string
object
String object also uses c-style strings internally.
#include<string>
string str = "Ball";
str[0] = 'C'; // mutable!
str.length() == str.size() //true; both are equivalent
str.substr(begin, end)
str.compare(str1, str2) //lexicographic comparison
// C-strings
char* str = "Abhi"; //Immutable
char str[] = "Abhi"; //Mutable; size = 5 (includes '\0' by default in size)
#include <iomanip> // for setpricision, setw
cout << num << setprecision(4); //number of decimal places = 4
setw(n) : set width for the next I/O operation, resets after each operation
//to read only 3 chars from cin into areaCode we can use:
cin >> setw(3) >> areaCode;
cout << set2(2) << 12345; //won't truncate since width < input_length
#include<iostream>
cout << boolalpha << (4 > 1); //print bool as true/false rather than numeric/0
// in declaration
int foo(int = 3)
// in definition
int foo(int a = 3)
// Function can then be called by skipping default arguments in the call too (obviously!)
Function Overloading: based on parameter (TYPE or ARITY); a function cannot be overloaded only by its return type only. Name mangling happens in background for overloaded funcitons.
Function Templating:
template <class T>
T sum(T a, T b){
return a+b;
}
x = sum(2, 7)
x = sum(2.0, 5.77)
// we can use keyword "typename" instead of "class" too in above example
// Non-type templates:
template <class T, int N>
T fixed_multiply (T val){ return val * N; }
fixed_multiply<int, 2>(10)
// we can't pass variables in second argument of template since the code for this is generated and is hardcoded (as 2) during compile-time itself and during runtime call is made for "val" argument only
// funtions can be overloaded based on "const-ness" of the parameters only if the const parameter is a reference or a pointer
void foo(int a){ }
void foo(const int a) { } // no overloading; compile-error
void bar(int* p){ }
void bar(const int* p){ } // allowed
void foobar() const{
cout<<"Hello";
}
// a const function specifies that it cannot modify any attributes of the object on which they are called
// const objects cannot call non-const functions; consts functions can be called from any object, const and non-const
namespace foobar{
int foo(){ return 5; }
int a, b;
}
int main{
foobar::a = 2;
foobar::foo();
using foobar::a; // declaring a single variable in a scope with "using"
using namespace b; // declaring entire namespce with "using namespace"
// namespace declaration in a block confines it to local scope
Aliasing: namespace new_name = current_name;
Declaring namespaces twice willl merge them:
namespace a{ int a; }
namespace b{ int b; }
namespace a{ int c; }
nullptr
keywordint* p = nullptr; //same as 0 or NULL
References (&): aliasing; just like pointers but referencing and dereferencing are implicitly taken care of
Downcasting of const
is error in C++ (unlike C): See here
const int a = 3;
int * p = nullptr;
p = &a; // error
new
: returns pointer, initializes allocated space with garbage value(s)a = new int;
foo = new (nothrow) int [5]; // won't throw error if fails to allocate; will return a NUll pointer
delete a;
int *arr = new int[10];
int *p = new int[5] {1, 2, 3, 4, 5}; // init
delete[] arr;
for (int n : nums) //read-only by default
for(int &n: nums) //need to use references for mutability
- Storage Duration: determines the duration of a variable, i.e., when it is created and when it is destroyed.
Automatic (local), Static(global, static, namespace) and Dynamic(new, malloc)
- Scope: Local and Global (determines which parts of the program can reference the variable)
- Linkage: Internal(local, static) and External(extern)
Static storage (global, static, namespace): Initialized to 0, allocated for the whole duration of program
Automatic storage (local): Initialized to garbage value, allocated for the duration of block execution only
auto // meaning changed since C++11
typedef // not a storage class in C++
register // deprecated since C++11
static, extern
mutable // used in struct or class to indicate that a data member is modifiable even though the object is declared const
thread_local
// CV-Qualifiers
const, volatile
Note that the C++ compiler generate a version of the code for each type used in the program, in a process known as “instantiation of template”
// template<typename T> on both declaration and definition
// Multiple types
template<typename T, class U, ...>
T sum(T a, U b){
cout << "Generic" << "\n" ;
return a + b;
}
// Function Calling
// 1. Let compiler decide types
sum(2, 7) // (int, int)
sum(2.0, 6) // (sdouble, int)
// 2. Explicitly declare types on call
sum<int, int>(2, 7)
sum<double, int>(2.0, 6)
#include <iostream>
using namespace std;
template<typename T>
T sum(T a, T b){
cout << "Generic" << "\n" ;
return a + b;
}
template<>
int sum<int>(int a, int b){
cout << "Specialized" << "\n";
return a + b;
}
int sum(int a, int b){
cout << "Normal" << "\n";
return a + b;
}
int main() {
cout << sum(2, 7);
}
// Precedence: Normal > Specialized > Generic
template <typename T>
class Number {
//body
};
// Have to use template on each of method definitions outside of the class.
template <typename T>
T Number<T>::getValue() {
return value;
}