CS Engineering Gyan

Classes and Objects in C++

In the previous chapter, we looked at Object Oriented Programming from a conceptual level, understanding why it exists and briefly touching on classes and objects along with the four core pillars. Now it is time to get hands-on and explore classes and objects properly, since almost everything else in object-oriented C++ is built directly on top of these two ideas.

A class is the actual code construct in C++ used to define a new custom data type. It describes what kind of data a group of related objects will hold, and what actions those objects will be able to perform. Once a class is defined, it does not occupy any memory by itself, since it is simply a description. Memory is only reserved once an object, meaning a real instance of that class, is actually created.

In this tutorial, you will learn how to properly define a class, how access specifiers control visibility of data and functions, how member functions work, how constructors and destructors manage an object's life cycle, and how the special this pointer is used inside a class.


Defining a Class in C++

A class definition begins with the class keyword, followed by the class name, and a body enclosed in curly braces that lists the data members and member functions belonging to that class. A semicolon is always required after the closing brace, which is a detail beginners often forget.

Syntax

class ClassName {

    // data members

    // member functions

};

Example

#include <iostream>

using namespace std;

class Video {

    public:

        string title;

        int views;

        void display() {

            cout << "Title: " << title << ", Views: " << views << endl;

        }

};

int main() {

    string channel = "CS Engineering Gyan";

    Video lecture;

    lecture.title = "Classes and Objects";

    lecture.views = 2700;

    cout << channel << " new video:" << endl;

    lecture.display();

    return 0;

}

Output

CS Engineering Gyan new video:

Title: Classes and Objects, Views: 2700

Here, Video is a class containing two data members, title and views, along with a member function called display. The object lecture is created from this class and used to store real data specific to one particular video.


Creating Objects

Once a class has been defined, you can create as many objects from it as needed, and each object maintains its own independent copy of the class's data members, even though they all share the same member functions.

Example

#include <iostream>

using namespace std;

class Video {

    public:

        string title;

        int views;

};

int main() {

    string channel = "CS Engineering Gyan";

    Video video1;

    video1.title = "Pointers in C++";

    video1.views = 5200;

    Video video2;

    video2.title = "Object Oriented Programming";

    video2.views = 3400;

    cout << channel << " video 1: " << video1.title << " (" << video1.views << " views)" << endl;

    cout << channel << " video 2: " << video2.title << " (" << video2.views << " views)" << endl;

    return 0;

}

Output

CS Engineering Gyan video 1: Pointers in C++ (5200 views)

CS Engineering Gyan video 2: Object Oriented Programming (3400 views)

Even though video1 and video2 are both created from the same Video class, they hold completely separate data. Changing the title or views of one object has no effect whatsoever on the other.


Access Specifiers

Access specifiers control which parts of a class can be accessed from outside the class itself. C++ provides three access specifiers, and understanding the difference between them is essential for applying encapsulation properly.

Access Specifier Description
public Members can be accessed directly from outside the class.
private Members can only be accessed from within the class itself, by default.
protected Members can be accessed within the class and by classes that inherit from it.

Example

#include <iostream>

using namespace std;

class Channel {

    private:

        int subscriberCount;

    public:

        void setSubscribers(int count) {

            subscriberCount = count;

        }

        int getSubscribers() {

            return subscriberCount;

        }

};

int main() {

    string channelName = "CS Engineering Gyan";

    Channel csEngineeringGyan;

    csEngineeringGyan.setSubscribers(60000);

    cout << channelName << " subscribers: " << csEngineeringGyan.getSubscribers() << endl;

    return 0;

}

Output

CS Engineering Gyan subscribers: 60000

Since subscriberCount is private, it cannot be accessed directly using something like csEngineeringGyan.subscriberCount from outside the class. Instead, the public functions setSubscribers and getSubscribers act as controlled entry points, which is a practical demonstration of encapsulation.

It is worth noting that by default, class members in C++ are private if no access specifier is mentioned, unlike structures, where members default to public. This is one of the small but important differences between the class and struct keywords in C++.


Member Functions

A member function is simply a function that is defined inside a class and operates on the data members of that class. Member functions can either be defined directly inside the class body, or declared inside the class and defined separately outside of it using the scope resolution operator.

Example: Defining a Member Function Outside the Class

#include <iostream>

using namespace std;

class Playlist {

    public:

        string name;

        int videoCount;

        void showDetails();

};

void Playlist::showDetails() {

    cout << "Playlist: " << name << ", Videos: " << videoCount << endl;

}

int main() {

    string channel = "CS Engineering Gyan";

    Playlist dsaPlaylist;

    dsaPlaylist.name = "DSA Series";

    dsaPlaylist.videoCount = 25;

    cout << channel << " playlist update:" << endl;

    dsaPlaylist.showDetails();

    return 0;

}

Output

CS Engineering Gyan playlist update:

Playlist: DSA Series, Videos: 25

The scope resolution operator, written as two colons, tells the compiler that the showDetails function being defined outside the class body actually belongs to the Playlist class. This style is common in larger projects, where class declarations are kept in one file and their implementations in another.


Constructors

A constructor is a special member function that runs automatically whenever an object of a class is created. Constructors are typically used to initialize the data members of an object with meaningful starting values, removing the need to set them manually every single time.

A constructor always shares the exact same name as the class itself, and it never has a return type, not even void.

Example

#include <iostream>

using namespace std;

class Video {

    public:

        string title;

        int views;

        Video(string videoTitle, int initialViews) {

            title = videoTitle;

            views = initialViews;

            cout << "New video object created" << endl;

        }

};

int main() {

    string channel = "CS Engineering Gyan";

    Video newUpload("Classes and Objects", 100);

    cout << channel << " uploaded: " << newUpload.title << " with " << newUpload.views << " views" << endl;

    return 0;

}

Output

New video object created

CS Engineering Gyan uploaded: Classes and Objects with 100 views

This particular constructor is called a parameterized constructor, since it accepts arguments and uses them to set up the object's initial state at the moment of creation. C++ also allows a default constructor, which takes no parameters at all, and is automatically provided by the compiler if no constructor is written manually.

Example: Default Constructor

#include <iostream>

using namespace std;

class Comment {

    public:

        Comment() {

            cout << "A new comment object has been created" << endl;

        }

};

int main() {

    string channel = "CS Engineering Gyan";

    cout << channel << " comment section activity:" << endl;

    Comment newComment;

    return 0;

}

Output

CS Engineering Gyan comment section activity:

A new comment object has been created

Destructors

A destructor is another special member function that is automatically called when an object goes out of scope or is explicitly deleted, and it is typically used to perform cleanup tasks before the object is destroyed, such as releasing dynamically allocated memory.

A destructor shares the class name preceded by a tilde symbol, takes no parameters, and cannot be overloaded, meaning a class can have only one destructor.

Example

#include <iostream>

using namespace std;

class Session {

    public:

        Session() {

            cout << "Viewer session started" << endl;

        }

        ~Session() {

            cout << "Viewer session ended" << endl;

        }

};

int main() {

    string channel = "CS Engineering Gyan";

    cout << channel << " tracking a viewer session:" << endl;

    Session viewerSession;

    cout << "Viewer is watching the video" << endl;

    return 0;

}

Output

CS Engineering Gyan tracking a viewer session:

Viewer session started

Viewer is watching the video

Viewer session ended

Notice that the destructor runs automatically right before the program ends, at the point where viewerSession goes out of scope, without needing to be called explicitly anywhere in the code.


The this Pointer

Inside any non-static member function, C++ automatically provides a special pointer called this, which points to the specific object that the member function is currently operating on. This becomes especially useful when a constructor's parameter name is the same as a data member's name.

Example

#include <iostream>

using namespace std;

class Channel {

    public:

        string name;

        Channel(string name) {

            this->name = name;

        }

        void showName() {

            cout << "Channel name: " << this->name << endl;

        }

};

int main() {

    Channel csEngineeringGyan("CS Engineering Gyan");

    csEngineeringGyan.showName();

    return 0;

}

Output

Channel name: CS Engineering Gyan

Here, the constructor parameter is also named name, which matches the data member's name exactly. Writing this->name makes it clear that we are referring to the object's own data member, rather than the local parameter, resolving what would otherwise be a naming conflict.


Objects as Function Arguments

Just like ordinary variables, objects can also be passed to functions, either by value, where a copy of the object is made, or by reference, where the function operates directly on the original object.

Example

#include <iostream>

using namespace std;

class Video {

    public:

        string title;

        int likes;

};

void addBonusLikes(Video& v) {

    v.likes += 50;

}

int main() {

    string channel = "CS Engineering Gyan";

    Video featuredVideo;

    featuredVideo.title = "Constructors Explained";

    featuredVideo.likes = 300;

    addBonusLikes(featuredVideo);

    cout << channel << " " << featuredVideo.title << " likes after bonus: " << featuredVideo.likes << endl;

    return 0;

}

Output

CS Engineering Gyan Constructors Explained likes after bonus: 350

Because the function accepts the object by reference, using an ampersand in the parameter type, any change made inside the function is reflected in the original object back in main, rather than being lost on a temporary copy.


Advantages and Limitations of Classes and Objects

Advantages Limitations
Group related data and behavior into a single, organized unit. Overusing classes for very simple tasks can add unnecessary structure.
Constructors and destructors automate setup and cleanup work. Poorly designed constructors can make objects harder to create correctly.
Access specifiers protect internal data from unwanted external changes. Beginners may find access specifier rules confusing at first.

Best Practices While Using Classes and Objects


Common Mistakes Beginners Make

Mistake Correct Practice
Forgetting the semicolon after the closing brace of a class definition. Always end a class definition with a semicolon.
Trying to access private members directly from outside the class. Use public member functions to interact with private data.
Giving a constructor a return type by mistake. Remember that constructors never have a return type, not even void.
Assuming a struct behaves exactly like a class in every way. Remember that struct members are public by default, while class members are private by default.

Frequently Asked Interview Questions

  1. What is a class in C++?
    A class is a user-defined blueprint that describes the data members and member functions a group of related objects will have.
  2. What is an object in C++?
    An object is a real instance created from a class, with its own actual values stored in memory.
  3. What is a constructor?
    A constructor is a special member function that runs automatically when an object is created, usually to initialize its data.
  4. What is a destructor?
    A destructor is a special member function that runs automatically when an object is destroyed, usually to perform cleanup tasks.
  5. What is the default access specifier in a C++ class?
    Members of a class are private by default if no access specifier is explicitly mentioned.
  6. What is the this pointer used for?
    The this pointer refers to the current object inside a member function, and is often used to resolve naming conflicts with parameters.
  7. Can a class have more than one constructor?
    Yes, a class can have multiple constructors with different parameter lists, a feature known as constructor overloading.
  8. What is the difference between a class and a struct in C++?
    The main difference is the default access level, since class members default to private while struct members default to public.

Summary

Classes and objects form the practical foundation of object-oriented programming in C++, turning the conceptual ideas discussed earlier into working code. A class defines the structure, while objects are the actual instances that carry real data and can be created, used, and destroyed throughout a program's execution.

Access specifiers, member functions, constructors, and destructors all work together to give a class full control over how its data is initialized, accessed, and cleaned up. The this pointer adds one more layer of clarity, letting a member function refer confidently to the exact object it is currently working with.

With a solid grasp of classes and objects, you are now ready to move on to inheritance in C++, where existing classes can be extended and specialized to build more powerful and reusable object hierarchies.


← Previous: Object Oriented Programming Next: Inheritance in C++ →

Home Visit Our YouTube Channel