C++ Revision

0.0(0)
studied byStudied by 0 people
0.0(0)
full-widthCall Kai
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
GameKnowt Play
Card Sorting

1/23

encourage image

There's no tags or description

Looks like no tags are added yet.

Study Analytics
Name
Mastery
Learn
Test
Matching
Spaced

No study sessions yet.

24 Terms

1
New cards

Constructors

Constructors helps to initialise the object of a class it’s can either accept an argument or not.  There can be many constructors in a class (overloaded)

eg: // in BankAccount.h
class BankAccount {
...
public:
BankAccount();
void deposit(double amount);
. . .
};
// in BankAccount.cpp
BankAccount::BankAccount() {
balance_ = 0.0;
owner_ = "";
}

Multiple Constructors: BankAccount::BankAccount() {
balance_ = 0.0;
owner_ = "";
}
BankAccount::BankAccount(string name) {
balance_ = 0.0;
owner_ = name;
}
BankAccount::BankAccount(double v, string name){
balance_ = v;
owner_ = name;
}

 

2
New cards

Constructors with Arguments

A constructor is Invoked automatically whenever a class instance is created.

A constructor with no argument is called a default constructor. In a constructor each class member has their own default constructor called: 

 class Bank {
public:
Bank(); // Bank’s constructor
// it invokes BankAccount constructor
// (100 times) before running itself
private:
BankAccount accounts_[100];
};

Members can also be initialised in the initialiser list 

BankAccount::BankAccount() :
balance_(0.0), owner_("")
{
// nothing here
}

“new” is actually a two-step process:
• Allocate memory for the object, then
• The constructor of the object is called
• Might be the default constructor
BankAccount
bp; //constructor not called
bp = new BankAccount; // constructor called
BankAccount
allAccounts = new
BankAccount[10]; // is constructor called?
• You can pass arguments to constructors, too
BankAccount* b1 = new BankAccount("J.
Smith", 5.00);

3
New cards

Destructors

Destructor is a function that is automatically called when a class instance is destroyed

class BankAccount {
public:
BankAccount();
. . .
~BankAccount();
};

Delete is a two step process:

  • Call destructor of pointed to Object

  • Then release the memory Occupied by that object

When a constructor is invoked all member objects also have their destructors called (automatically)

4
New cards

Shallow Copy and Deep copying 

Means that C++ copies each member of the class individually when the classes are simple (uses this = for copying).

However when the class handles dynamically allocated memory we use Deep copying  (it’s allocated memory for the copy and then copies the actual values ). 

To allow deep copy to happen automatically we allow copy constructor - called automatically in certain cases where an object must be initialised from an existing object. 

If you don’t define your own copy constructor, the complier generates a default  copy constructor. To perform a deep copy you need to write your own copy constructors  

Possible solution (?): home-made copy() function
• Could use a client function:
void copy(const DynArray& from, DynArray&
to);
• Or a member function:
void DynArray::copy(const DynArray& other);
• Problems:
• Must be called explicitly; rely on user of this class to call it
• There are many scenarios where “hidden” copying is
performed
• By default, C++ performs all such copying using shallow copy

5
New cards

Technicalities of =    (THIS)

DynArray a2 = a1; is not the same

DynArray a2;
a2 = a1;

The first case the object is created with copy constructor. In the 2nd case the default constructor is used to create a2 then a1 is copied to the already - existing a2

The latter = is the copy assignment operator
• Overloaded operator=
• DynArray& DynArray::operator=(const
DynArray&);

  • This - a reserved word in C++ means a pointer to a current object Can be used like any other pointer
    DynArray *ap = this;
    if (ap == this){ … }

6
New cards

Copy Assignment operator

Copy Assignment operator :

4 Steps: Test for same objects if (&other != this) // ok to do copy

Delete old dynamically allocated data: Call some cleanup_() function, or
• directly: delete [] array_;

copy new data 

Return a reference to the current object - return *this;

Ways to Reduce Copy : Complier Optimisation

Move Semantics 

7
New cards

Class Relationship

Inheritance is the idea where one class is allowed to inherit the features

Has-a”: Class in a Class
class StudentCouncil
{
Student president_;
Student ministerOfPropaganda_;
Student membersAtLarge_[5];
};
of another class. 

8
New cards

Inheritance Terminology

A derived class inherits from a base class by putting
: public BaseClassName in the class
declaration
class Shark : public Fish {
// Shark-specific stuff here
};
// Shark is the derived class or
subclass
// Fish is the base class or superclass
• Shark declares that it “is-a-kind-of” Fish by inheriting
from Fish

  • Bank Account Inheritance:

class Account {
...
double balance_;
Customer owner_;
Date dataOpened_;
...
void makeDeposit (double amount);
...
};
class SavingsAccount : public Account {
// has all data members that Account has, plus has its own
double interestRate_;
// has all methods that Account has, plus has its own
void creditInterest();
};

9
New cards

Rules of Inheritance

All data and methods in base class are automatically
inherited by derived classes Derived class can add new functions or data Derived class can override base class functions

Subclass can only override functions, not data
members

10
New cards

Public/Private/Protected

Public members of base class: visible to derived
class and clients that use it
• Private members of base class: still not visible to
derived class or clients
• The private members are still there inside the derived
object! They just aren’t visible
• Protected members in base class: visible in derived
class, but not visible to clients

-Colour ColourPoint::getColour()
{
return colour_;
}
void ColourPoint::print()
{
cout << "(" << getX() << ", " << getY()
<< ")/" << colour_;
}
• Can’t use xpos_ and ypos_ directly if declared as
private in base class; hence getX() and getY()
• But ok if they are declared as protected

11
New cards

Inheritance


Use the :: scope resolution operator to explicitly call an
overridden method from the derived class
void ColourPoint::print()
{
Point::print(); // print x and y
cout << ", " << colour_;
}

C++ supports inheriting from multiple base classes
class Student { …} ;
class PhDStudent : public Student { …
};
class Staff { … };
class GTA : public Staff, public
PhDStudent { … } ;

Constructors are not inherited!

Constructor of base class is always called, before
constructor of derived class executes

12
New cards

Substituting

New notation: : baseclass(args, …) calls
base class parameterised constructor

An instance of a derived class can always be substituted for an instance of a base class

  • Derived class guaranteed to have at least the same data and interface as a base class 

If it’s true of a mammal, it’s true of a dog”
class Base { … };
Class Derived : public Base { … };
Base b;
Derived d;
b = d; // ok, but may lose stuff (slicing)
d = b; // not ok

13
New cards

Pointers and Inheritance

Same substitution rules applies to pointers/References : 

  • Base* b = new Derived(); // ok
    Derived* d = new Base(); // not ok

14
New cards

Static and Dynamic Types 

Every Variable has a Static and  Dynamic type. 

  • Static  type is declared type of variable. 

  • Dynamic type is type of object the variable actually contains or refers to. 

15
New cards

Dispatch

Dispatching is the act of deciding which piece of code to execute when a method is called.

  • Static dispatch means that the decision is made statically(at compiled time )

  • Point* p = new ColorPoint(3.14, 2.78,
    green);
    p->print();
    // p is a Point*, so call Point::print()

  • Dynamic Dispatch - If an overriding function exists, call it. The decision is made at run-time, sometimes called late binding. Supports Polymorphic behaviour 

  • Example of dynamic Dispatch:

class Point { // base class
public:
virtual void print();

};
class ColourPoint : public Point { // derived class
public:
void print() override;

};
Point *p = new ColorPoint(3.13, 5.66, blue);
p->print(); // calls ColorPoint::print()

16
New cards

The conditions for Dispatch 

Dynamic Dispatch only happens under these two conditions:

  • The objects is accessed through a pointer or reference

  • The function is Virtual

In any other cases you get static dispatch

Animal* zoo[20]; // array of 20 ptrs
for(Animal* p : zoo)
p->laugh();
• An array of pointers to objects derived from the same
base class
• All the objects pointed to are animals, but some might
be dogs, cats, hedgehogs…
• Each subclass might have its own methods for
behaviour like “scream” “fight” “laugh”…
• If I write zoo[i]->laugh() I want to get the
appropriate behaviour for that type of animal
• Won’t happen unless laugh() is virtual in Animal class

  • Dynamic Dispatch is slightly slower that static dispatch  

17
New cards

Virtual Destructors and Dynamic Cast

Each animal was created with their own constructor.

Destructors can also be made virtual like other functions

  • Upcasting: convert from derived to base class, ok
    • Use static_cast or even done implicitly
    Derived
    dp = …;
    Base
    bp = static_cast<Base*>(dp);
    • What about the other direction, downcasting?
    Base
    bp = …;
    Derived
    dp = static_cast<Derived*>(bp);
    • Unsafe: undefined behaviour if bp does not really point to
    Derived
    • Use dynamic_cast for run-time checking:
    Derived
    dp = dynamic_cast<Derived>(bp);
    • Returns nullptr if bp is not really a Derived*

18
New cards

Pure Virtual Functions
and Abstract Classes

An abstract Class is one that should not or cannot be instantiated- it only defines an interface. 

A concrete Class can have instances Classes are recognised as abstract if they have at least one pure virtual function 

A pure virtual function is a not implemented in the base class must be implemented in the derived classes syntax: append "= 0" to base method declaration
class Button {
public:
virtual void clicked() = 0;
};

Compiler guarantees that class with pure virtual
functions cannot be instantiated
• A call to a pure virtual function uses the version from
some derived class
class Exitbutton : public Button {
public:
void clicked(); //with implementation
};
Button *b = new Exitbutton();
b->clicked();s

19
New cards

Overloading

  • Different Functions can have same name if argument list is different.

  • To resolve mean to decide which version of the overloaded function is being called. This is determined by matching actual arguments against possible formal arguments

Example of resolving:

Function declarations
void snark(int);
void snark(double);
void snipe(char []);
void snipe(double);
void sneep(char);
void sneep(double);
snark(1); // Integer Snark
snipe(1); // Double Snipe
sneep(1); // Ambiguous

20
New cards

Overloading pt 2

  • Overriding - same function name and signature in derived class, overrides base class

  • Overloading - same function name and different signature

  • In C++ most operators can be overloaded just like functions

  • A class can designate another class or a standalone function
    as a friend
    • Grants access to private members to the friend
    • Friendships are neither reciprocated nor inherited
    class X {
    public: …
    private: …
    friend class Y;
    // Y can access X’s private members
    friend void f();
    // f() (not a member of X) can access X’s
    // private members
    };

  • eg

class Colour {
public:
Colour(int r, int g, int b);
// overload as member methods
Colour operator+(const Colour& rhs);
// overload as friend function
friend ostream& operator<<(ostream&, const Colour&
col);
private:
int r_, g_, b_;
};

Colour Colour::operator+(const Colour& rhs)
{
Colour c(*this);
c.r_ += rhs.r_;
c.g_ += rhs.g_;
c.b_ += rhs.b_;
return c;
}
ostream& operator<<(ostream& os, const Colour& col)
{
os << "R=" << col.r_ << ", B=" << col.b_
<< ", G=" << co.g_;
return os;
}

21
New cards

operators

operator functions can be implemented as
• members functions of a class
• or non-member functions, typically as friends

Sometimes implementing as non-members is useful when it
involves implicit conversions
class Rational {
int num; int denom;
…}
Rational operator+(const Rational& lhs, const
Rational& rhs);
• We want to be able to write e.g. 2 + 3/4
• Details omitted; see [Book: C++ for Java programmers Ch.5]
• Stream operators (<<, >>) are typically overloaded as non-
members

Related operators are not “automatically” overloaded
• E.g. if you overload +, it doesn’t mean += will automatically do the right
thing
• Likewise for != (doesn’t follow from
), < (doesn’t follow from >) etc
• Have to be overloaded explicitly and separately
• Although can reuse code, e.g.
bool operator
(const Colour& lhs, const Colour&
rhs) {
return (lhs.r_
rhs.r_ &&
lhs.g_
rhs.g_ &&
lhs.b_ == rhs.b_);
}
bool operator!=(const Colour& lhs, const Colour&
rhs) {
return !(lhs == rhs); // call the above
}

The array-indexing operator [] can be overloaded as
well
• Two versions:
Type operator[](int i) const;
// accessor
• (assuming Type is a primitive type)
Type& operator[](int i);
// mutator
• Return by reference so can be used like a[0]=1;
• Overload both; body likely identical.

22
New cards

Streams

Only need to decide if it’s input or output or both
• istream – allows reading from
• ostream – allows writing to
• iostream – allows both

Overloading << is an overloaded operator
ostream& operator<<(ostream& os, const
SomeClass& c)
{
return os << c.toString();
// assuming SomeClass has a
// toString() function
}
• os << x is actually operator<<(os, x)

23
New cards

Input Stream States


Each input stream has a state
• The state is good if every operation succeeds
• The state is bad if some operation failed
• Couldn’t open a file
• Couldn’t read in a value of the expected type
• Couldn’t find delimiting character for getline()
• The stream state is a boolean that we can test

Suppose we try to read an integer, but no integer is there
int age = -1;
cin >> age;
if (!cin)
{
// could not read the age, age still is -1
cout << "The age couldn't be read." << endl;
}

24
New cards

Dealing with Input Stream Errors

Once the input stream fails you can use clear()
to clear the input stream's fail state, but you must
also do something about the input that caused it to
fail; simply trying to read the input again with the
same input statement will cause it to fail again.

int num;
cout << "Enter an integer\n";
while (! (cin >> num) ) {
cin.clear();
cin.ignore(1000,'\n');
// ignore what’s typed until newline
// try without them and see what happens
cout << "Enter an integer\n";
}