Skip to content

Instantly share code, notes, and snippets.

@twentyse7en
Last active January 22, 2021 09:18
Show Gist options
  • Save twentyse7en/97706e9a2c91c035ffa6d28862c5377c to your computer and use it in GitHub Desktop.
Save twentyse7en/97706e9a2c91c035ffa6d28862c5377c to your computer and use it in GitHub Desktop.
Objected Oriented Programming

Objected oriented programming

Index

Intro

why you need to use this, observe the example

#include<bits/stdc++.h>

int main()
{
  // you have two player and their (x,y) coordinates and
  // speed. It become messy as the no. of players increase
  // also it's difficult to change the coordinates of the
  // players too.
  int player0_x, player0_y, player1_x, player1_y, speed1, speed2;
  
}

So what's a good way to do this ? Oops ofcourse!

#include<bits/stdc++.h>

class Player
{
  int x, y;
  int speed;
};

int main()
{ 
  // That's sooper neat!
  Player p1;
  p1.x = 5; // Nope! why? bcoz by default data is private
}

//==== for making it accessible ===========

class Player
{
  public:
    int x, y;
    int speed;
};

//=== methods =============================

/ what if you want to move the player

class Player
{
  public:
    int x, y;
    int speed;
    
    void Move(int xa, ya)
      {
        x += xa*speed;
        y += ya*speed;
      }
};

// for accesing inside methods
p1.Move(-1, 1);

Static for classes and struct

struct Player
{
    static int x, y;

    void Print()
    {
        cout << x << ", " << y << endl;
    }
};

We haven't defined the variables the caused the problems.
int Player::x;
int Player::y;

This solves it!

int main()
{
    Player p1;
    p1.x = 1, p1.y = 2;
    // alternatively you can do this
    Player p2;
    p2.x = 4;
    p2.y = 6;
    
    p1.Print();
    p2.Print();

    return 0;
}

// ouput:
// 4, 6
// 4, 6

Back to the static. When we made them static, there is only one instance of the variable across all the objects. Which caused the changing second objects changed the first one.

what if non-static member variable and static function? This causes trouble as it doesn't have no idea which object data should be used. Static method doesn't have a class instance.

struct Player
{
    int x, y;

    static void Print()
    {
        cout << x << ", " << y << endl;
    }
};

Constructors

for more depth

It's a good practice to intialize data iniside the class or it will contain garbage value. So how to you do that?

struct Player
{
    int x, y;
    
    // no return type needed
    // just class/struct name
    // this fun will do the work
    Player()
    {
        x = 0;
        y = 0;
    }


    void Print()
    {
        cout << x << ", " << y << endl;
    }
};

Also you can overwrite the function if you want to provide the arguments

    Player()
    {
        x = 0;
        y = 0;
    }

    Player(int i, int j)
    {
        x = i;
        y = j;
    }

// use Player p1(10, 20);

Destructor

The evil twin of Constructor. It is called when the function get deleted. let's see an example/

    //...
    // this is how you construct a destructor
    ~Player()
    {
        cout << "This is player is Dead!" << endl;
    }
    //...

// Object is deleted when exiting the fn()
void fn()
{
    Player p1;
    p1.Print();
}

Inheritance

In principle, a publicly derived class inherits access to every member of a base class except:

- its constructors and its destructor
- its assignment operator members (operator=)
- its friends
- its private members

In depth

Inheritance always us to have a hierarchy of classes which relates to each other. In other words it allow us to have a base class which contains common functionality, then we can branch off from that class and create new sub classes from initial class.

- It avoid code code duplication - more..
\\ This makes sense as the car is subclass of vehicle 
\\ in the real life, so we can kinda mimic
class Vehicle
{
    public:
        int model_no, reg_no, distance;
    
        void Move(int travelled)
            {
                distance += travelled;
                cout << "LOG: Distance " << distance << endl;
            }
};

class Car: public Vehicle
{
    public:
        string s = "Vehicle";
        bool airbag;
        
        void PrintName()
        {
            cout << s << endl;
        }
 };

Virtual Function

We can override a function from base class in the derived class.

class Vehicle
{
    public:
        string GetName() 
        {
            return "Vehicle";
        }
};

class Car: public Vehicle
{
    public:
        \\ GetName is redefined
        string GetName()
        {
            return "Car";
        }
 };

int main()
{
    Vehicle v1;
    Car c1;
    cout << v1.GetName() << endl;
    cout << c1.GetName() << endl; 
    return 0;
}

Ouput:
Vehicle
Car

So why do we need virtual function?

C++ Allow us to use Base class pointer to refer derived class. But output is different from what we expect.

\\ Baseclass pointer is used
void Print(Vehicle *p)
{
    cout << p->GetName() << endl;
}

int main()
{
    Vehicle v1;
    Car c1;
    Print(&c1);
    Print(&v1);
    return 0;
}

output:
Vehicle
Vehicle

This result may not be quite what you were expecting at first! By using virtual function we can use the function from derived class.

class Vehicle
{
    public:
        // virtual keyword to indicate this can be redefined
        // in the derived class
        virtual string GetName() 
        {
            return "Vehicle";
        }
};

class Car: public Vehicle
{
    public:
        // override keyword is not necessary
        // But it is clear that this  fn
        // is a redefinition of function from
        // Base class
        string GetName() override
        {
            return "Car";
        }
 };

How virtual function work in background

  • Whenever a program has a virtual function declared, a v-table is constructed for the class. The v-table consists of addresses to the virtual functions for classes that contain one or more virtual functions. Note that virtual tables are class specific, i.e., there is only one virtual table for a class irrespective of the number of virtual functions it contains.
  • The object of the class containing the virtual function contains a virtual pointer that points to the base address of the virtual table in memory. Whenever there is a virtual function call, the v-table is used to resolve to the function address. An object of the class that contains one or more virtual functions contains a virtual pointer called the vptr at the very beginning of the object in the memory.

Abstact class (Pure virtual function)

Why?

Sometimes implementation of all function cannot be provided in a base class because we don’t know the implementation. Such a class is called abstract class. For example, let Shape be a base class. We cannot provide implementation of function draw() in Shape, but we know every derived class must have implementation of draw().

// An abstract class 
class Test 
{    
   // Data members of class 
public: 
   // Pure Virtual Function 
   virtual void show() = 0; 
   
  /* Other members */
}; 

Friend function and friend class

In principle, private and protected members of a class cannot be accessed from outside the same class in which they are declared. However, this rule does not apply to "friends".

Friends are functions or classes declared with the friend keyword.

A non-member function can access the private and protected members of a class if it is declared a friend of that class. That is done by including a declaration of this external function within the class, and preceding it with the keyword friend:

#include <iostream>
using namespace std;

class Rectangle
{
    private:
        int width, height;

    public:
        Rectangle() 
        {
        }
        
        Rectangle(int w, int h)
            : width(w), height(h)
        {
        }

        int area()
        {
            return width * height;
        }

};


Rectangle createCopy(const Rectangle &r1)
{
    Rectangle r2;
    r2.width = r1.width;
    r2.height = r1.height;
    return r2;
}


int main()
{
    Rectangle foo(1, 2);
    Rectangle bar;

    bar = createCopy(foo);

    cout << bar.area() << endl;

}

This will throw you an error as the `createDuplicate` can't access the private fuction.

\...
class Rectangle
{
    private:
        int width, height;

    public:
        Rectangle() 
        {
        }
        
        Rectangle(int w, int h)
            : width(w), height(h)
        {
        }

        int area()
        {
            return width * height;
        }
        
        // small change
        friend Rectangle createCopy(const Rectangle&);
};

\...

By refering the fuction as a friend, now the fucntion can access the private members. Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both.

Friend class
friend class keyword is used.

\\ Here two points need special attention
\\ 1. class Square is declared initially, this is necessary as Recatangle uses Square
\\ 2. Rectangle::convert() is declared and implemented later as the function requires
\\ complete implementaion of the Square

#include <iostream>
using namespace std;

class Square;

class Rectangle
{
    private:
        int width, height;

    public:
        Rectangle() 
        {
        }
        
        Rectangle(int w, int h)
            : width(w), height(h)
        {
        }

        void convert(Square s);
        
        int area()
        {
           return width * height ;
        }
};

class Square
{
    friend class Rectangle;

    private:
        int side;

    public:
        Square(int x)
            :side(x)
        {}
    
};

void Rectangle::convert(Square s)
{
    width = s.side;
    height = s.side;
}

int main()
{
    Rectangle foo(1, 2);
    Square bar(7);

    foo.convert(bar);
    cout << "Area " << foo.area() << endl;
}

TODO:

  • Add the details in the GFG
  • read
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment