const safe:
#include<iostream>
using namespace std;
class A{
int ia;
public:
void setA(const int a){
ia = a;
}
int getA() const {
/* const-safe functions:
* won't change anything;
* const object may only use const safe methods in the class
*/
cout << "this is the const getA()" << endl;
return ia;
}
int getA() {
cout << "this is the mutable getA()" << endl;
return ia;
}
};
int main(){
A a;
a.setA(47);
const A b = a;
cout <<"a is " << a.getA() << endl; //prefer the mutable version
cout <<"b is " << b.getA() << endl; //only allowed to call const version
}
a is this is the mutable getA()
47
b is this is the const getA()
47
Namespace and class to basic types
#include<iostream>
namespace BWString{
const std::string bws = "This is BWString::string";
class string{
std::string s;
public:
string (void) : s(bws) {};
string (const std::string & s) : s(bws) {};
operator std::string & (void) {return s;}
/*operator Type(void) {
......
return TypeValue;
}
*/
};
}
BWString::string s1("This is a string");
int main(int args, char** argv){
std::string s=s1;
std::cout<< s << std::endl;
return 0;
}
This is BWString::string
Explicit vs Implicit Conversion:
#include<iostream>
class Rational{
int _n;
int _d;
public:
Rational(int numerator=0, int denominator=1):_n(numerator), _d(denominator){
std::cout << "parameter constructor" << std::endl;
};
Rational(const Rational & rhs):_n(rhs._n), _d(rhs._d) {
std::cout << "copy constructor" << std::endl;
};
~Rational();
inline int numerator() const {return _n;}
inline int denominator() const {return _d;}
Rational & operator = (const Rational & rhs) ;
Rational operator + (const Rational & rhs) const;
};
Rational & Rational::operator = (const Rational & rhs){
if(this != &rhs){
std::cout << "assignment" << std::endl;
_n = rhs._n;
_d = rhs._d;
}
return *this;
}
Rational Rational::operator + (const Rational & rhs) const{
return Rational(_n*rhs._d + _d*rhs._n, _d*rhs._d);
}
Rational::~Rational(){
std::cout << "destructor: " << _n << "/" << _d << std::endl;
}
std::ostream & operator << (std::ostream & o, const Rational & rhs){
return o << rhs.numerator() << "/" << rhs.denominator(); //
}
int main(int args, char** argv){
using namespace std;
Rational a = 7; //parameter constructor
cout << "a is: " << a << endl;
return 0;
}
OUTPUT:
parameter constructor
a is: 7/1
destructor: 7/1
#include<iostream>
class Rational{
int _n;
int _d;
public:
explicit Rational(int numerator=0, int denominator=1):_n(numerator), _d(denominator){
std::cout << "parameter constructor" << std::endl;
};
Rational(const Rational & rhs):_n(rhs._n), _d(rhs._d) {
std::cout << "copy constructor" << std::endl;
};
~Rational();
inline int numerator() const {return _n;}
inline int denominator() const {return _d;}
Rational & operator = (const Rational & rhs) ;
Rational operator + (const Rational & rhs) const;
};
Rational & Rational::operator = (const Rational & rhs){
if(this != &rhs){
std::cout << "assignment" << std::endl;
_n = rhs._n;
_d = rhs._d;
}
return *this;
}
Rational Rational::operator + (const Rational & rhs) const{
return Rational(_n*rhs._d + _d*rhs._n, _d*rhs._d);
}
Rational::~Rational(){
std::cout << "destructor: " << _n << "/" << _d << std::endl;
}
std::ostream & operator << (std::ostream & o, const Rational & rhs){
return o << rhs.numerator() << "/" << rhs.denominator(); //
}
int main(int args, char** argv){
using namespace std;
//Rational a = Rational(7); //parameter constructor
Rational a(7);
cout << "a is: " << a << endl;
return 0;
}
OUTPUT:
parameter constructor
a is: 7/1
destructor: 7/1
#include<iostream>
const std::size_t maxlen = 1024;
class BWSize{
std::size_t _size;
public:
explicit BWSize(const std::size_t);
explicit BWSize(const char *);
std::size_t size() const;
};
BWSize::BWSize(const std::size_t n){
std::cout << "BWSize from int" << std::endl;
_size = n <= maxlen ? n:0;
}
BWSize::BWSize(const char* s){
std::cout << "constructor: BWSize from c-string" << std::endl;
for(std::size_t i=0; i < maxlen; i++){
if(!s[i]){
_size = i;
return;
}
}
_size = 0;
}
std::size_t BWSize::size() const{
return _size;
}
using namespace std;
void func(const BWSize & s){
cout << "s.size is " << s.size() << endl;
}
int main(){
//BWSize s = 'x'; implicit conversion
//BWSize s = (size_t) 120; doesn't work; we have parameterized constructor not copy constructor
BWSize s((size_t)125);
cout << "s.size is " << s.size() << endl;
//func('x'); implicit conversion
func(BWSize("xxxxx"));
return 0;
}
BWSize from int
s.size is 125
constructor: BWSize from c-string
s.size is 5
__________________________________________________________________________________________________________________________________________Animal Class:
#include<iostream>
using namespace std;
const static string unk = "unknow";
const static string clone_prefix = "clone-";
class Animal{
string _type;
string _name;
string _sound;
public:
Animal();
Animal(const string & type, const string & name, const string & sound);
Animal(const Animal &);
Animal & operator=(const Animal &);
~Animal();
void print() const;
};
Animal::Animal(): _type(unk), _name(unk), _sound(unk){
cout << "default constructor" << endl;
}
Animal::Animal(const string & type, const string & name, const string & sound)
:_type(type), _name(name), _sound(sound){
cout << "constructor with arguments" << endl;
}
Animal::Animal(const Animal & a){
cout << "copy constructor" << endl;
_type = a._type;
_name = clone_prefix + a._name;
_sound = a._sound;
}
Animal::~Animal(){
cout << "destructor: "
<< _name << ", the " << _type
<<endl;
}
void Animal::print() const{
cout << _name << ", the " << _type
<<", says " << _sound << endl;
}
Animal & Animal::operator=(const Animal & o){ //
cout << "assignment operator" << endl;
if(this != &o){
_name = clone_prefix + o._name;
_type = o._type;
_sound = o._sound;
}
return *this;
}
int main(int args, char** argv){
Animal a;
a.print();
const Animal b("goat", "bob", "baah");
b.print();
const Animal c = b;
c.print();
a = c;
a.print();
return 0;
}
default constructor
unknow, the unknow, says unknow
constructor with arguments
bob, the goat, says baah
copy constructor
clone-bob, the goat, says baah
assignment operator
clone-clone-bob, the goat, says baah
destructor: clone-bob, the goat
destructor: bob, the goat
destructor: clone-clone-bob, the goat
Complex class (friend function overload)
#include<iostream>
using namespace std;
class Complex{
double _real, _image;
public:
Complex(double r = 0, double i = 0);
void print() const;
friend Complex operator+(const Complex & lhs, const Complex & rhs); //overloading non-member function declared in Complex class
friend Complex operator-(const Complex & lhs, const Complex & rhs);
friend Complex operator-(const Complex & c);
};
Complex::Complex(double r, double i):_real(r), _image(i) {};
void Complex::print() const{
cout << "(" << _real << "," << _image << ")" << endl;
}
Complex operator+(const Complex & rhs, const Complex & lhs){
double r = rhs._real + lhs._real;
double i = rhs._image + lhs._image;
return Complex(r, i);
}
Complex operator-(const Complex & rhs, const Complex & lhs){
double r = rhs._real - lhs._real;
double i = rhs._image - lhs._image;
return Complex(r, i);
}
Complex operator-(const Complex & c){;
return Complex(-c._real, -c._image);
}
int main(){
Complex c1(2.5, 3.7), c2(4.2, 6.5);
Complex c;
c = c1 - c2;
c.print();
c = 25 + c2;
c.print();
c = c2 + 25;
c.print();
c = -c1;
c.print();
return 0;
}
(-1.7,-2.8)
(29.2,6.5)
(29.2,6.5)
(-2.5,-3.7)
Rational:
#include<iostream>
class Rational{
int _n;
int _d;
public:
Rational(int numerator=0, int denominator=1):_n(numerator), _d(denominator){
//std::cout << "parameter constructor" << std::endl;
};
Rational(const Rational & rhs):_n(rhs._n), _d(rhs._d) {
//std::cout << "copy constructor" << std::endl;
};
~Rational();
inline int numerator() const {return _n;}
inline int denominator() const {return _d;}
Rational & operator = (const Rational & rhs) ;
Rational operator - (const Rational & rhs) const;
Rational operator * (const Rational & rhs) const;
Rational operator / (const Rational & rhs) const;
operator std::string (void) const;
};
Rational & Rational::operator = (const Rational & rhs){
if(this != &rhs){
std::cout << "assignment" << std::endl;
_n = rhs._n;
_d = rhs._d;
}
return *this;
}
Rational Rational::operator - (const Rational & rhs) const{
return Rational(_n*rhs._d - _d*rhs._n, _d*rhs._d);
}
Rational Rational::operator * (const Rational & rhs) const{
return Rational(_n*rhs._n, _d*rhs._d);
}
Rational Rational::operator / (const Rational & rhs) const{
return Rational(_n*rhs._d, _d*rhs._n);
}
Rational::~Rational(){
std::cout << "destructor: " << _n << "/" << _d << std::endl;
}
std::ostream & operator << (std::ostream & o, const Rational & rhs){
return o << rhs.numerator() << "/" << rhs.denominator(); //
}
Rational operator + (const Rational & lhs, const Rational & rhs) {
return Rational(lhs.numerator()*rhs.denominator() + lhs.denominator()*rhs.numerator(),
lhs.denominator()*rhs.denominator());
}
Rational::operator std::string (void) const{
const static int maxstring = 64;
char s[maxstring];
snprintf(s, maxstring, "%d/%d", _n, _d);
return std::string(s);
}
int main(int args, char** argv){
using namespace std;
Rational a = 7; //parameter constructor
cout << "a is: " << a << endl;
Rational b(5, 3);
cout << "b is: " << b << endl;
Rational c = b;
cout << "c is: " << c << endl;
Rational d;
cout << "d is: " << d << endl;
d = c;
cout << "d is: " << d << endl;
Rational & e = d;
d = e;
cout << "e is: " << e << endl;
cout << a << " + " << b << " = " << a+b << endl;
cout << a << " - " << b << " = " << a-b << endl;
cout << a << " * " << b << " = " << a*b << endl;
cout << a << " / " << b << " = " << a/b << endl;
cout << 25 << " + " << b << " = " << 25+b << endl;
string s = "Rational as a string: ";
s += b;
cout << s << endl;
return 0;
}
a is: 7/1
b is: 5/3
c is: 5/3
d is: 0/1
assignment
d is: 5/3
e is: 5/3
7/1 + 5/3 = 26/3
destructor: 26/3
7/1 - 5/3 = 16/3
destructor: 16/3
7/1 * 5/3 = 35/3
destructor: 35/3
7/1 / 5/3 = 21/5
destructor: 21/5
25 + 5/3 = 80/3
destructor: 80/3
destructor: 25/1
Rational as a string: 5/3
destructor: 5/3
destructor: 5/3
destructor: 5/3
destructor: 7/1
new-delete
#include <iostream>
using namespace std;
class A {
int _a;
int _b;
int _c;
public:
A( int );
~A();
int a() { return _a; }
int b() { return _b; }
int c() { return _c; }
};
A::A( int i = 0 ) : _a(i), _b(i + 1), _c(i + 2) {
cout << "A constructor called" << endl;
}
A::~A() {
cout << "A destructor called" << endl;
}
int main( int argc, char ** argv ) {
cout << "allocating space for one A object" << endl;
A * a = new (nothrow) A[5]; //A * a = new (nothrow) A(5);
if(a == nullptr) {
cerr << "new A failed." << endl;
return 1;
}
for(int i=0; i < 5; ++i){
printf("a: %d, %d, %d\n", a[i].a(), a[i].b(), a[i].c());
}
delete[] a;
cout << "space for A object deleted" << endl;
//printf("a: %d, %d, %d\n", a->a(), a->b(), a->c());
//delete a;return 0;}
allocating space for one A objectA constructor calledA constructor calledA constructor calledA constructor calledA constructor calleda: 0, 1, 2a: 0, 1, 2a: 0, 1, 2a: 0, 1, 2a: 0, 1, 2A destructor calledA destructor calledA destructor calledA destructor calledA destructor calledspace for A object deleted
Exceptions:
#include<iostream>
#include<exception>
using namespace std;
static string unk = "unknown";
static string clone_prefix = "clone-";
class E: public exception{
const char* msg;
E() {};
public:
//throw() specifies what exceptions are allowed to be thrown from inside this function
//and the list is empty, which means it does not allow any exceptions
//to be thrown from inside this function
//-> exception class does not throw any exception to prevent recursion
E(const char* s) throw(): msg(s) {};
const char* what() const throw() { return msg; }
};
class Animal{
string _type, _name, _sound;
public:
Animal();
explicit Animal(const string & type, const string & name, const string & sound);
Animal(const Animal &);
Animal & operator = (const Animal & rhs);
~Animal();
void print() const;
};
Animal:: Animal(): _type(unk), _name(unk), _sound(unk) {
cout << "default constructor" << endl;
};
Animal:: Animal(const string & type, const string & name, const string & sound)
:_type(type), _name(name), _sound(sound) {
if(!(type.length() && name.length() && sound.length())){
throw E("Insufficient parameters");
}else{
cout << "constructor with parameters" << endl;
}
};
Animal:: Animal(const Animal & rhs)
:_type(rhs._type), _name(rhs._name), _sound(rhs._sound) {};
Animal & Animal::operator = (const Animal & rhs){
if(this != &rhs){
cout << "Assignment operator" << endl;
_type = rhs._type;
_name = clone_prefix + rhs._name;
_sound = rhs._sound;
}
return *this;
}
Animal::~Animal(){
cout << _name << ", the " << _type << endl;
}
void Animal::print(void) const{
cout << _name << ", the " << _type << ", says " << _sound << endl;
}
int main(){
try{
Animal x("bear", "bill", "");
x.print();
} catch(exception & e){ //exception & e
cerr << "Animal x: " << e.what() << endl;
}
return 0;
}
Animal x: Insufficient parameters
__________________________________________________________________________________________________________________________________________
Class inheritance: base/super/parent class, derived/sub/child class
specifier | base class | derived class | other objects |
public | 1 | 1 | 1 |
protected | 1 | 1 | |
private | 1 |
friend declaration guarantees private member access to functions and classes
polymorphism:
generic pointer(pointer to base class) , virtual method + virtual destructor(derived class destructor overloads the destructor in base class)
multiple inheritance:
#include <iostream>
using namespace std;
// Base class
class Animal {
string _name;
string _type;
string _sound;
// private constructor prevents construction of base class
Animal(){};
protected:
// protected constructor for use by derived classes
Animal ( const string & n, const string & t, const string & s )
: _name(n), _type(t), _sound(s) {}
public:
void speak() const;
const string & name() const { return _name; }
const string & type() const { return _type; }
const string & sound() const { return _sound; }
};
void Animal::speak() const {
printf("%s the %s says %s\n", _name.c_str(), _type.c_str(), _sound.c_str());
}
class Fur{
string _type;
Fur() {};
protected:
Fur(const string & f): _type(f) {}
public:
const string & type() {return _type;}
};
// Dog class - derived from Animal
class Dog : public Animal {
int walked;
public:
Dog( string n ) : Animal(n, "dog", "woof"), walked(0) {};
int walk() { return ++walked; }
};
// Cat class - derived from Animal
class Cat : public Animal, public Fur {
int petted;
public:
Cat( string n ) : Animal(n, "cat", "meow"), Fur("silky"), petted(0) {};
int pet() { return ++petted; }
void grooming();
};
void Cat::grooming(){
cout << Animal::name() << " grooms her" << Fur::type() << " fur" << endl;
}
// Pig class - derived from Animal
class Pig : public Animal {
int fed;
public:
Pig( string n) : Animal(n, "pig", "oink"), fed(0) {};
int feed() { return ++fed; }
};
int main( int argc, char ** argv ) {
Dog d("Rover");
Cat c("Fluffy");
Pig p("Arnold");
d.speak();
c.speak();
p.speak();
cout << d.name() << " the dog has been walked " << d.walk() << " times" << endl;
cout << c.name() << " the cat has been petted " << c.pet() << " times" << endl;
cout << p.name() << " the pig has been fed " << p.feed() << " times" << endl;
c.grooming();
}
__________________________________________________________________________________________________________________________________________
generic programming
#include<iostream>
using namespace std;
template<typename Type>
Type maxof(Type a, Type b){
return (a > b? a: b);
}
int main(){
cout << maxof("aaaaa", "baaaa") << endl;
cout << maxof<string>("aaaaa", "baaaa") << endl;
return 0;
}
aaaaa
baaaa
#include<iostream>
#include<vector>
using namespace std;
//if sepT isn't specified, it will default to the value_type of the container type
template<typename cT, typename retT=cT, typename sepT=decltype(cT::value_type)>
retT joinContainer(const cT & o, const sepT & sep){
retT out;
auto it = o.begin();
while(it != o.end()){
out += *it;
if(++it != o.end()){
out += sep;
}
}
return out;
}
int main(){
string s1("This is a string");
string s2("This is also a string");
string s3("Yet another string");
cout << joinContainer(s1, ':') << endl;
vector<string> vs({s1, s2, s3});
cout << joinContainer<vector<string>, string>(vs, ", ") << endl;
return 0;
}
T:h:i:s: :i:s: :a: :s:t:r:i:n:g
This is a string, This is also a string, Yet another string
#include<iostream>
#include<exception>
class E: public std::exception{
const char * msg;
E() {};
public:
explicit E(const char * s) throw(): msg(s) {}
const char * what() const throw() { return msg; }
};
template<typename T>
class Stack{
static const int defaultSize = 100;
static const int maxSize = 1000;
int _size;
int _top;
T * stackPtr;
public:
explicit Stack(int s = defaultSize);
~Stack() { delete [] stackPtr; }
T & push(const T &);
T & pop();
bool isEmpty() const { return _top < 0; }
bool isFull() const { return _top + 1 >= _size ;}
int top() const { return _top; }
int size() const {return _size; }
};
template<typename T>
Stack<T>:: Stack(int s){
if(s > maxSize || s < 1){
throw E("Invalid stack size");
} else{
_size = s;
_top = -1;
stackPtr = new T[_size];
}
}
template<typename T>
T & Stack<T>::push(const T & i){
if(isFull()) { throw E("stack full"); }
else { return stackPtr[++_top] = i; }
}
template<typename T>
T & Stack<T>::pop(){
if(isEmpty()) { throw E("stack empty"); }
else { return stackPtr[_top--]; }
}
int main(int argc, char ** args){
using namespace std;
Stack<int> si(5);
cout << "si size: " << si.size() << endl;
cout << "si top: " << si.top() << endl;
si.push(1);
si.push(2);
si.push(3);
si.push(4);
si.push(5);
cout << "si after pushes: " << si.top() << endl;
cout << "si is " << (si.isFull()? "" : "not ") << "full" << endl;
while(!si.isEmpty()){
cout << "popped " << si.pop() << endl;
}
}
si size: 5
si top: -1
si after pushes: 4
si is full
popped 5
popped 4
popped 3
popped 2
popped 1