[C++] OOPS concepts

This blog covers some OOPS concepts, and some sample I/O covering the constructor call order. This is basically just my notes after reading about these concepts. I’m kinda saving it here, because CC has nice markdown, and I figured it might also be helpful for others. So let’s go.

What is a Class?

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions (also called member variables and member functions) as its members.
Source: Wiki

The member functions are also called ‘methods’, and I will be referring to them as ‘methods’ for the course of this tutorial.

Example Class
class Entity {
    int x, y;
    string name;

    void increment() {
        x++;
        y++;
    }
};

Visibility

  1. Private: Can be accessed only within the class, or a friend class.
  2. Protected: Can be accessed by the class, and any derived class.
  3. Public: Can be accessed from anywhere.

I will not be going through constructors and destructors. You can look them up here.

Difference between Class and Struct

In C++, there is none. They are exactly the one and the same, except for one small difference. In a class, the default visibility is private:, while in a struct, it is public:.

Good Stuff

Static members and methods

Static members and methods can be seen as a global variable/function for a class. There is only one instance of static variables/functions for a particular class.

class Entity {
public:
	static int x;
	int z;
	static func() { cout << x << endl; }
};

int main() {
	Entity a, b;
	a.x = 4;
	cout << a.x << endl;
	b.x = 27;
	cout << a.x << endl;
	b.func();
}

OUTPUT:
4
27
27

When we are dealing with static members/methods, it doesn’t make sense to acces them through an object (nevertheless that’s completely allowed).

Entity::x = 4;
cout << a.x << endl;
Entity::x = 27;
cout << a.x << endl;
Entity::func();

Makes more sense.

As there is only one instance of a static method, static methods can only access static variables. Because, if I access z inside the function func(), the compiler doesn’t really know which object’s z to call. Using z inside func() will throw a compile error.

Inheritance

You can have a new class, that derives data members and methods from a base class. You can access the members of the base class A, through an object of B.

class A {
public:
	A() { cout << "Constructed A\n";}
	int x, y;
	int sum() {return x + y;}
	~A() { cout << "Destructed A\n";}
};

class B : public A {
public:
	B() { cout << "Constructed B\n";}
	int z;
	void init() {z = sum();}
	~B() { cout << "Destructed B\n";}
};

int main() {
	B obj;
	obj.x = 1;
	obj.y = 2;
	obj.init();
	cout << obj.z << endl;
}
Constructed A
Constructed B
3
Destructed B
Destructed A 

Whenever an object of the inherited class is constructed, a base class is also constructed implicitly, and liked to the the inherited class. We can also declare a base class object, just like any normal class, but we cannot access the members of B.

A obj;
obj.z = 10;

This code gives a compile error, error: class A has no member z.

Overriding

A base class function can be overriden, to do something else in a derived class.

class A {
public:
	void getName(){ cout << "This is class A\n"; }
};

class B : public A {
public:
	void getName(){ cout << "This is class B\n"; }
};

int main() {
	A obja;
	B objb;
	obja.getName();
	objb.getName();
}
OUTPUT:
This is class A
This is class B

Polymorphism

C++ allows a derived class pointer to be used in place of a base class pointer. This property of an object oriented programming language is called Polymorphism.

class A {
public:
	void getName(){ cout << "This is class A\n"; }
};

class B : public A {
public:
	void getName(){ cout << "This is class B\n"; }
};

void print(A* obj) {
	obj->getName();
}

int main() {
	A* obja;
	B* objb;
	print(obja);
	print(objb);
}

The code compiles successfully. But! Take a look at the output.

OUTPUT:
This is class A
This is class A

When we pass a derived calss pointer, the program still calls the base classs function, and not the overridden function. This is because the bindings are made during compile time. To overcome this, we have to use virtual functions.

class A {
public:
	virtual void getName(){ cout << "This is class A\n"; }
};

class B : public A {
public:
	void getName() override { cout << "This is class B\n"; }
};

void print(A* obj) {
	obj->getName();
}

int main() {
	A* obja;
	B* objb;
	print(obja);
	print(objb);
}
OUTPUT:
This is class A
This is class B

The override keyword is optional, but it gives more clarity while looking at a code.

Note: Override function cannot have a different return type. If it has different arguments then…
It’s not related to the base class anymore. It’s simply a new overloaded function, you might as well treat it as a separate function defined in the derived class.

Initializer List

class Entity {
public:
    Entity() { puts("Default Constructor"); }
    Entity(int x) { puts("Parameterized Constructor"); }
};

class A {
    int x;
    Entity e; // Default Constructor NOT called for case 1.
    // Case 1:
    A() : e(12) {}; 
    // Case 2:
    A() { e = Entity(12); }
    // Parameterized Constructor called in both cases.
};

OUTPUT:
// Case 1: (Because of initializer list property)
Parameterized Constructor
// Case 2:
Default Constructor
Parameterized Constructor

Memory Allocatiion

Stack:

Stack allocation of memory is what we always do. Any variable that you normally declare is allocated on the stack, and it dies as soon as the scope ends.

// Stack Allocation
int* a;
*a = 3;
// Heap Allocation
int * a = new int;
*a = 3;
...
delete a; // Do not forget to free the heap memory.

Heap:

If you allocate memory in the heap, it stays forever, even after the scope where it was initialized. To de-allocate the memory, we have to manually do it, by calling delete. Otherwise, we will have memory leaks. In Java or C#, there is no stack. Everything is allocated on the heap. So there is no need to delete it, as these languages are well managed, and they take care of this for you.

Entity* e = new Entity; // Constructor Call
Entity* e = (Entity*)malloc(sizeof(Entity)); // No constructor call

delete e // Destructor Call
free(e); // No Destructor Call

More on this

An example:

class Entity {
public:
	Entity () { cout << "Constructing\n";;}
	~Entity() {cout << "Gone\n"; }
};

int main() {
	Entity* ptr;
	{
		Entity e;
		ptr = &e;
	}
	puts("Case 1:");
	{
		Entity* e = new Entity;
		ptr = e;
	}
	puts("Case 2:");
	delete ptr;
}
OUTPUT:
Constructing
Gone
Case 1:
Constructing
Case 2:
Gone

If you replace delete ptr with free(ptr), the memory will be freed, but the destructor will not be called. (Meaning Gone will not be printed.)
Similarly, the constructor will not be called if we use malloc(sizeof(Entity)), instead of new.

Note that the return type of malloc() is a void*, and it has to be casted to Entity*. (To use it properly. You can of course leave it as a void*, you’ll just get a compile time warning. But…, don’t do that.)

TODO: Copy constructors, Multiple Inheritance, Virtual Inheritance.
(I might add these in a few days).

This is a very small portion mostly based off of Cherno’s Playlist. If you’d like to learn more stuff like this, check it out.

24 Likes

Thanks for the informational article.
could you please explain me why declaring the method as private in derived class which is overridden and calling using base class pointer invokes the method of the derrived class??

class Base
{
     public:
        virtual void disp(){ cout<<"inside the base";}
};
class Derived:public Base
{
   private:
   void disp(){cout<<"inside derrived";}
}

main()
{
   Base* bp = new Derived();
    bp->disp();
}

OUTPUT: inside derrived ??? But how it is private in the derrived class!!..
Please explain this behaviour.

Thanks

2 Likes

Interesting behavior. I really have no idea how this is happening. :no_mouth:.

1 Like

Is it a bug in c++?

What do you think the behaviour should be?

2 Likes

Compiler error? Trying to access a private function of class derived.

[EDIT]: Or not. The function is actually public in base. It’s definition is overridden by whatever is written in derived. Nice.

Compiler error on which line?

Edit:

What if I had:

void f(Base* bp)
{
    bp->disp();
}

int main()
{
    Base* bp = new Derived();
    f(bp);
}
2 Likes

The article is so informative and wonderfully compiled together with all necessary exclusives Aneeee.

1 Like

Yes got it. So it tries to access the function in Base class. But as it’s a virtual function, and the object is derived class, the definition is overridden with what we have defined in Derived. The visibility is still public.

Am I right?

Ish :slight_smile: It’s more that accessibility of virtual functions is not stored in the vtable, so the dynamic dispatch simply doesn’t know or care about the accessibility of the overridden method. This design decision is almost certainly based around performance considerations.

As to why a derived class is allowed to override a function and reduce its accessibility in the first place … I’ve not seen a particularly compelling reason for why. See e.g.

The best answer seems to be “they couldn’t be bothered to ban it :man_shrugging:” XD

3 Likes

@aneee004 is making Codechef discuss more informative and better everyday. Nice job buddy and keep posting such articles🙂

2 Likes

Bookmarked!

1 Like

Thanks for the informational article.
could you please explain me How should I RESTRICT Derived class to inherit/override any PURE virtual function coming from the base class.

class Base
{
     public:
        virtual void disp() = 0;
        virtual void show()=0;
};

class Derived:public Base
{
   // Here I dont want to get the disp() pure virtual function from Base class
   public:
       void show() {cout<<"show from derrived";}

}

Basically I want to take only specific function(show()) from the Base class but I dont want to have disp() in my derived class.


Thanks

That’s why you should use the override specifier. It makes the code easier to read and if wrongly marked, the compiler will shout at you for good like this:

error: ‘void Derived::disp()’ marked ‘override’, but does not override

:slightly_smiling_face:

3 Likes

Thanks. By my question was how should I avoid disp() to get inherited in the derived class?

I’m assuming you want to do so without touching the contents of Base and Derived because I don’t think it makes much sense otherwise. How about using a Bridge?

#include <iostream>
#include <cassert>

using namespace std;

class Base
{
     public:
        virtual void disp() = 0;
        virtual void show()=0;
};

class Bridge : public Base
{
    private:
        void disp() override { assert(false and "plz don't call"); }
};

class Derived:public Bridge
{
   // Here I dont want to get the disp() pure virtual function from Base class
   public:
       void show() {cout<<"show from derrived";}

};
2 Likes

I don’t think you can avoid any function. That’s the whole point of inheritance. You inherit from the base class to extend upon what’s already there. If you don’t want to use the disp function from the base class, you can always choose not to, or you can override it to do nothing in the derived class. (Or maybe throw a nullpointer and cause an RE).

Thanks for the insights , yes bridges would definitely resolve the issue . :slight_smile:

1 Like

Thanks consept

1 Like

Thanks for giving insights