Paramclasses Academy - Blog

Tutorials Details

←
Post 11 of 13
→

What is Classes and Objects in C++

What is Classes and Objects in C++

October 15, 2026

Classes and objects are the foundation of object-oriented programming (OOP) in C++. They allow you to combine data and the functions that operate on that data into a single unit.

In Module 10, you learned how struct groups related information. Now, you’ll learn how classes can also control access to data, protect an object's internal state, and organize larger programs.

1. Learning objectives

By the end of this module, you will be able to:

  • Define a class and create objects.

  • Understand the difference between a class and an object.

  • Use public, private, and protected access specifiers.

  • Write member functions inside and outside a class.

  • Create constructors and use constructor overloading.

  • Use the this pointer.

  • Apply encapsulation with getters and setters.

  • Work with multiple objects and static members.

  • Build a simple bank account management program.

Estimated time

75–100 minutes

Prerequisites

Structures, functions, variables, and basic C++ syntax

2. What is a class?

A class is a user-defined type that describes the data and behavior its objects can have.

An object is an instance of a class.

For example, imagine a class called Student. It may have data such as a student's name and marks, along with functions to display the student’s details or update the marks.

Class: Student

Data members

  • name

  • marks

    Member functions

  • display()

  • updateMarks()

Creates instances

Object s1

Aman, 85

Object s2

Priya, 92

Both objects share the same class definition, but each normally has its own non-static member data.

A useful analogy is a building blueprint: the class is the blueprint, while objects are the individual buildings constructed from it.

3. Class syntax in C++

The general syntax is:

class ClassName {
private:
    // Data members and helper functions

public:
    // Functions and operations accessible to users
};

Important rules:

  • Use the class keyword to define a class.

  • The class body is enclosed in braces {}.

  • A class definition ends with a semicolon.

  • private members can be accessed directly only from permitted class contexts, such as the class's own member functions and friends.

  • public members form the interface that users of the class can access.

Example 1 — Your first class


#include <iostream>
#include <string>
using namespace std;

class Student {
public:
    string name;
    int marks;

    void display() {
        cout << "Name: " << name << endl;
        cout << "Marks: " << marks << endl;
    }
};

int main() {
    Student s1;

    s1.name = "Aman";
    s1.marks = 85;

    s1.display();

    return 0;
}

Output

Name: Aman
Marks: 85

Explanation:

  1. class Student defines the class.

  2. name and marks are data members.

  3. display() is a member function.

  4. Student s1; creates an object.

  5. s1.display() calls the function on that object.

This is a simple introductory example. In a well-encapsulated class, data is often private and accessed through public functions.

4. Objects and member access

An object is created using the class name followed by a variable name.

Student s1;
Student s2;

When members are public, use the dot operator (.) to access them through an object:

s1.name = "Aman";
s2.name = "Priya";

Each object has its own non-static data members. Updating s1.name does not change s2.name.

Example 2 — Multiple objects


#include <iostream>
#include <string>
using namespace std;

class Student {
public:
    string name;
    int marks;

    void display() {
        cout << name << " scored " << marks << endl;
    }
};

int main() {
    Student s1;
    Student s2;

    s1.name = "Aman";
    s1.marks = 85;

    s2.name = "Priya";
    s2.marks = 92;

    s1.display();
    s2.display();

    return 0;
}

Output

Aman scored 85
Priya scored 92

5. Access specifiers: public, private, and protected

Access specifiers control which parts of a program can access class members.

public

Members can be accessed from code that has access to the object.

private

Members can be accessed directly by the class's own member functions and friends, but not by ordinary external code.

protected

Members can be accessed by the class's member functions and friends, and by derived classes in permitted contexts. Ordinary external code cannot access them directly.

Important default rule: Members of a class are private by default. Members of a struct are public by default.

Example 3 — Private data


#include <iostream>
using namespace std;

class BankAccount {
private:
    double balance = 1000.0;

public:
    void displayBalance() {
        cout << "Balance: " << balance << endl;
    }
};

int main() {
    BankAccount account;

    account.displayBalance();

    // account.balance = 5000; // Error: private member

    return 0;
}

Output

Balance: 1000

The object can call displayBalance() because it is public. It cannot directly access balance because that member is private.

This helps protect an object's internal state from unintended changes.

6. Encapsulation: protecting data

Encapsulation means combining data and the operations that work on it while controlling how the data can be accessed.

For example, a bank account should not allow arbitrary code to set its balance to an invalid value. Instead, public functions can enforce rules.

Example 4 — Getters and setters

A getter reads a value. A setter updates a value, often after validating it.


#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;
    int marks = 0;

public:
    void setName(const string& studentName) {
        name = studentName;
    }

    void setMarks(int studentMarks) {
        if (studentMarks >= 0 && studentMarks <= 100) {
            marks = studentMarks;
        } else {
            cout << "Invalid marks!" << endl;
        }
    }

    string getName() const {
        return name;
    }

    int getMarks() const {
        return marks;
    }
};

int main() {
    Student s1;

    s1.setName("Aman");
    s1.setMarks(88);

    cout << "Name: " << s1.getName() << endl;
    cout << "Marks: " << s1.getMarks() << endl;

    s1.setMarks(150);

    cout << "Final marks: " << s1.getMarks() << endl;

    return 0;
}

Output

Name: Aman
Marks: 88
Invalid marks!
Final marks: 88

Why is this better?

  • marks is private.

  • setMarks() accepts only values between 0 and 100.

  • An invalid update is rejected.

  • getMarks() const reads the value without modifying the object.

Notice the const after a member function's parentheses. It promises that the function will not modify the object's ordinary non-mutable data members.

7. Member functions inside and outside a class

Member functions can be defined inside the class body or declared inside and defined outside the class.

A. Define the function inside the class

class Calculator {
public:
    int add(int a, int b) {
        return a + b;
    }
};

B. Define the function outside the class

Use the scope resolution operator (::) to indicate which class the function belongs to.


#include <iostream>
using namespace std;

class Calculator {
public:
    int add(int a, int b);
};

int Calculator::add(int a, int b) {
    return a + b;
}

int main() {
    Calculator calc;

    cout << calc.add(10, 20) << endl;

    return 0;
}

Output

30

In this example:

  • int add(int a, int b); declares the member function.

  • Calculator::add(...) defines that function outside the class.

  • :: associates the definition with Calculator.

Separating declarations and definitions can make larger projects easier to organize.

8. Constructors

A constructor is a special member function that initializes an object when it is created.

Constructor rules:

  • Its name matches the class name.

  • It has no return type—not even void.

  • It runs automatically when an object is initialized.

  • A class can have multiple constructors with different parameter lists.

Example 5 — A parameterized constructor


#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;
    int marks;

public:
    Student(string studentName, int studentMarks) {
        name = studentName;
        marks = studentMarks;
    }

    void display() const {
        cout << name << " scored " << marks << endl;
    }
};

int main() {
    Student s1("Aman", 85);
    Student s2("Priya", 92);

    s1.display();
    s2.display();

    return 0;
}

Output

Aman scored 85
Priya scored 92

The constructor initializes each object's data when it is created.

Constructor initializer lists

In modern C++, initializer lists are usually preferred for initializing data members.

Student(string studentName, int studentMarks)
    : name(studentName), marks(studentMarks) {
}

The part after : is called the member initializer list. It initializes the members directly, rather than default-initializing them and assigning new values afterward.

Initializer lists are required for certain members, such as reference members and const data members, and are also important for class-type members.

9. Types of constructors

A. Default constructor

A default constructor can be called without arguments.

class Box {
private:
    int length;

public:
    Box() : length(1) {}

    void display() const {
        cout << length << endl;
    }
};

Usage:

Box b;
b.display();

Output:

1

If you declare your own constructor with parameters, C++ generally will not automatically provide a default constructor. You can define one explicitly if needed.

B. Parameterized constructor

A parameterized constructor accepts values when creating an object.

class Box {
private:
    int length;

public:
    Box(int value) : length(value) {}
};

Usage:

Box b(10);

C. Constructor overloading

A class can provide more than one constructor, as long as their parameter lists differ.


#include <iostream>
using namespace std;

class Box {
private:
    int length;
    int width;

public:
    Box() : length(1), width(1) {}

    Box(int side) : length(side), width(side) {}

    Box(int l, int w) : length(l), width(w) {}

    int area() const {
        return length * width;
    }
};

int main() {
    Box b1;
    Box b2(5);
    Box b3(4, 6);

    cout << b1.area() << endl;
    cout << b2.area() << endl;
    cout << b3.area() << endl;

    return 0;
}

Output

1
25
24

The compiler selects the constructor that matches the arguments supplied.

10. The this pointer

Inside a non-static member function, this is a pointer to the current object.

It is especially useful when parameter names and member names are the same.

Example 6 — Using this


#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;

public:
    void setName(string name) {
        this->name = name;
    }

    void display() const {
        cout << name << endl;
    }
};

int main() {
    Student s1;

    s1.setName("Aman");
    s1.display();

    return 0;
}

Output

Aman

In this->name = name;:

  • this->name refers to the current object's data member.

  • name refers to the function parameter.

The this pointer is available in non-static member functions. It is not available in static member functions because those functions do not operate on one particular object through an implicit this pointer.

11. Static data members and static member functions

A normal data member belongs to each object separately. A static data member belongs to the class and is shared by all its objects.

Example 7 — Count the number of objects


#include <iostream>
using namespace std;

class Student {
private:
    inline static int count = 0;

public:
    Student() {
        count++;
    }

    static int getCount() {
        return count;
    }
};

int main() {
    Student s1;
    Student s2;
    Student s3;

    cout << "Objects created: "
         << Student::getCount() << endl;

    return 0;
}

Output

Objects created: 3

Explanation:

  • inline static int count = 0; defines one shared counter. Inline static data members are supported in C++17 and later.

  • Each constructor call increments that shared counter.

  • Student::getCount() calls a static member function using the class name and scope resolution operator.

  • A static member function can directly access static members, but it cannot directly access non-static members without an object.

For older C++ standards, a static data member generally needs a separate definition outside the class, such as int Student::count = 0;, in one source file.

12. Destructors: cleaning up objects

A destructor is a special member function that runs when an object's lifetime ends. It is commonly used to release resources owned by the object, although modern C++ often relies on standard library types that manage resources automatically.

A destructor:

  • Has the class name preceded by ~.

  • Has no return type.

  • Takes no parameters.

  • Cannot be overloaded.

Example 8 — Destructor demonstration


#include <iostream>
using namespace std;

class Demo {
public:
    Demo() {
        cout << "Constructor called" << endl;
    }

    ~Demo() {
        cout << "Destructor called" << endl;
    }
};

int main() {
    Demo d;
    cout << "Inside main" << endl;

    return 0;
}

Output

Constructor called
Inside main
Destructor called

The local object d is destroyed when its scope ends. Its destructor runs automatically.

For a simple class that only stores an int or a string, you usually do not need to write a custom destructor. The members manage their own lifetimes. This is one reason modern C++ favors resource-managing library types over manually allocated memory.

13. Mini project — Bank account system

Now combine classes, private data, constructors, validation, and member functions into a practical program.

Features:

  • Store an account holder's name and balance.

  • Deposit money.

  • Withdraw money if sufficient funds are available.

  • Display the current balance.


#include <iostream>
#include <string>
using namespace std;

class BankAccount {
private:
    string holderName;
    double balance;

public:
    BankAccount(const string& name, double initialBalance)
        : holderName(name),
          balance(initialBalance >= 0 ? initialBalance : 0) {
    }

    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposit successful." << endl;
        } else {
            cout << "Invalid deposit amount." << endl;
        }
    }

    void withdraw(double amount) {
        if (amount <= 0) {
            cout << "Invalid withdrawal amount." << endl;
        } else if (amount > balance) {
            cout << "Insufficient balance." << endl;
        } else {
            balance -= amount;
            cout << "Withdrawal successful." << endl;
        }
    }

    void display() const {
        cout << "Account holder: " << holderName << endl;
        cout << "Balance: " << balance << endl;
    }
};

int main() {
    BankAccount account("Aman", 1000);

    account.display();

    account.deposit(500);
    account.withdraw(200);
    account.withdraw(2000);

    cout << "\nFinal account details:" << endl;
    account.display();

    return 0;
}

Expected output

Account holder: Aman
Balance: 1000
Deposit successful.
Withdrawal successful.
Insufficient balance.

Final account details:
Account holder: Aman
Balance: 1300

Project breakdown

  1. holderName and balance are private, so external code cannot modify them directly.

  2. The constructor initializes the account and prevents a negative starting balance.

  3. deposit() accepts only positive amounts.

  4. withdraw() rejects invalid amounts and withdrawals exceeding the available balance.

  5. display() const shows the current state without modifying it.

This is a learning example, not a production banking system. Real financial applications require stronger validation, precise monetary representations, persistence, authorization, and transaction safeguards.

Project extension challenges

Try adding these features:

  • Add a unique account number.

  • Add a transfer function that moves money between two accounts.

  • Keep a transaction history.

  • Add a function that returns the balance.

  • Add a menu-driven interface using a loop and switch.

14. Common mistakes

Mistake 1 — Forgetting the class semicolon

Incorrect:

class Student {
public:
    int marks;
}

Correct:

class Student {
public:
    int marks;
};

Mistake 2 — Accessing private members directly

class Account {
private:
    int balance = 100;
};

Account a;
// cout << a.balance;  // Error

Provide an appropriate public member function to expose the required operation or information.

Mistake 3 — Giving a constructor a return type

class Student {
public:
    // void Student() {} // This is not a constructor
    Student() {}
};

A constructor has the class name and no return type.

Mistake 4 — Confusing . and ->

Student s;
Student* ptr = &s;

s.marks = 80;
ptr->marks = 90;

Use . with an object and -> with a pointer to an object.

Mistake 5 — Assuming a parameter changes the original object

Passing Student s by value creates a copy. If a function needs to modify the caller's object, use a suitable reference parameter such as Student& s.

Mistake 6 — Overlooking initialization

Prefer constructors, default member initializers, or value initialization such as Student s{}; to ensure built-in data members have defined starting values.

15. Hands-on exercises

Try these exercises before checking the solutions.

Exercise 1 — Rectangle class

Create a Rectangle class with private length and width members. Add a constructor and a public function that returns the area.

Hint: Area = length × width.

Exercise 2 — Employee salary

Create an Employee class with private name and salary members. Initialize them using a constructor and provide a public function to display the employee details.

Hint: Use a constant reference for a string constructor parameter if you want to avoid copying the argument unnecessarily.

Exercise 3 — Counter class

Create a Counter class with a private integer and public functions increment(), reset(), and getValue().

Hint: Keep the counter data private and modify it through member functions.

Exercise 4 — Constructor overloading

Create a Box class with constructors that accept no arguments, one dimension, or two dimensions. Add an area() function.

Hint: Use three distinct parameter lists and initialize members in initializer lists.

Exercise 5 — Validated marks

Create a Student class with private marks. Add a setter that accepts marks only in the range 0–100 and a getter to return the current marks.

Hint: Reject invalid values without changing the previous valid marks.

Show exercise solutions

16. Interactive knowledge-check quiz

Test your understanding of classes and objects, access control, constructors, encapsulation, and member functions.

Given class Box { int length; };, what is the default access level of length?

1 of 8

Aprotected

Bpublic

Cstatic

Dprivate

Next

17. Module 11 completion checklist

Mark each topic as you master it.

Your progress

0 of 12

Explain the difference between a class and an object.

Create objects and access public members.

Explain public, private, and protected access.

Use encapsulation with getters, setters, and validation.

Declare and define member functions inside and outside a class.

Write default and parameterized constructors.

Use constructor overloading and initializer lists.

Explain the this pointer.

Use static data members and static member functions.

Explain when destructors run.

Complete the Bank Account System mini project.

Pass the interactive quiz and solve the exercises.

What is Classes and Objects in C# ?

What is Classes and Objects in C# ?

October 26, 2026

Introduction

Classes and objects are two of the most important concepts in C# programming. They are the foundation of Object-Oriented Programming (OOP), which helps developers organize code, represent real-world entities, and build maintainable applications.

Whether you are developing a student management system, an e-commerce website, a banking application, or an enterprise software solution, you will frequently work with classes and objects.

In this tutorial, you will learn what classes and objects are, how to create them in C#, how to define fields, properties, methods, and constructors, and how to use multiple objects in practical programs.

What you will learn:

  • What a class is in C#

  • What an object is and how it differs from a class

  • How to create classes and instantiate objects

  • How to use fields, properties, and methods

  • How constructors initialize objects

  • How to create and work with multiple objects

  • How static and instance members differ

  • How to use object initializers

  • How to build a practical Student Management example

  • Common mistakes and best practices

1. What Is a Class in C#?

A class is a blueprint or template used to define the data and behavior that its objects can have.

A class can contain fields, properties, methods, constructors, events, and other members. These members describe what an object stores and what it can do.

For example, imagine a car manufacturing company. The company first creates a design that specifies the car's features, such as its color, model, and speed. Different cars can then be manufactured using that design.

In C#, the class represents the design, while each individual car is an object created from that class.

Basic syntax of a class

class Car
{
    public string Brand;
    public string Color;

    public void Start()
    {
        Console.WriteLine("The car has started.");
    }
}

In this example:

  • class is the keyword used to declare a class.

  • Car is the class name.

  • Brand and Color are fields that store data.

  • Start() is a method that defines behavior.

  • The public keyword makes these members accessible from other code where the class is accessible.

Important: Defining a class does not automatically create a separate car object. You must create an instance of the class to work with its instance members.

2. What Is an Object in C#?

An object is an instance of a class. It represents a specific entity with its own instance data and access to the behavior defined by its class.

For example, a Car class can be used to create a red car and a blue car. Both objects share the structure defined by Car, but they can store different values.

Creating an object

using System;

class Car
{
    public string Brand;
    public string Color;

    public void DisplayInfo()
    {
        Console.WriteLine("Brand: " + Brand);
        Console.WriteLine("Color: " + Color);
    }
}

class Program
{
    static void Main()
    {
        Car car1 = new Car();

        car1.Brand = "Toyota";
        car1.Color = "White";

        car1.DisplayInfo();
    }
}

Output:

Brand: Toyota
Color: White

Understanding the object creation statement

Car car1 = new Car();

This statement has three important parts:

  • Car — the type of the variable.

  • car1 — a variable that stores a reference to the object.

  • new Car() — creates a new Car instance and invokes its constructor.

The variable car1 is not the object itself; it holds a reference to the object.

3. Class vs Object in C#

Classes and objects are closely related, but they have different purposes.

Class Object
Defines a type or blueprint. Is an instance of a type.
Declares the available members. Uses the members through an instance reference.
Defines the structure for instance data. Stores its own instance data.
Can be declared without creating an instance. Must be created or obtained before it can be used.
Example: Car Example: new Car()

Consider this example:

class Student
{
    public string Name;
    public int Age;
}

Here, Student is the class. The following statements create two separate objects:

Student student1 = new Student();
Student student2 = new Student();

student1.Name = "Rahul";
student1.Age = 20;

student2.Name = "Priya";
student2.Age = 22;

Both objects follow the same class definition, but each has its own instance fields.

4. Fields in a C# Class

A field is a variable declared directly inside a class or struct. Fields can store data associated with an instance or with the type itself when declared static.

Example:

class Employee
{
    public string Name;
    public int Age;
    public double Salary;
}

Creating and using an employee object:

Employee employee = new Employee();

employee.Name = "Amit";
employee.Age = 28;
employee.Salary = 45000;

Console.WriteLine(employee.Name);
Console.WriteLine(employee.Age);
Console.WriteLine(employee.Salary);

Output:

Amit
28
45000

For many application-level classes, properties are preferred for public data access because they provide more flexibility for validation and future changes. Fields are still useful for internal implementation details and simple data storage.

5. Properties in C#

A property provides a controlled way to read or assign a value. It looks similar to a field when used, but it can contain accessors that execute code.

Example:

class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

The get accessor reads the property value, and the set accessor assigns a value.

Using the properties:

Student student = new Student();

student.Name = "Neha";
student.Age = 21;

Console.WriteLine(student.Name);
Console.WriteLine(student.Age);

Why use properties instead of public fields?

Properties allow you to control how values are read or updated.

class Product
{
    public string Name { get; set; }

    private decimal price;

    public decimal Price
    {
        get
        {
            return price;
        }
        set
        {
            if (value >= 0)
            {
                price = value;
            }
        }
    }
}

In this example, Price rejects negative values. The private field price stores the accepted value.

Product product = new Product();

product.Name = "Keyboard";
product.Price = 1500;
product.Price = -200;

Console.WriteLine(product.Price);

Output:

1500

The negative assignment is ignored by this implementation. In a production application, you might instead throw an exception or return a validation result so the caller knows the value was rejected.

6. Methods in a C# Class

A method defines an operation that a class or its objects can perform.

For example, a bank account might support depositing money, withdrawing money, and displaying its balance.

class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Multiply(int a, int b)
    {
        return a * b;
    }
}

Using the methods:

Calculator calculator = new Calculator();

int sum = calculator.Add(10, 20);
int product = calculator.Multiply(5, 4);

Console.WriteLine("Sum: " + sum);
Console.WriteLine("Product: " + product);

Output:

Sum: 30
Product: 20

The methods belong to the Calculator type. In this example, they are instance methods, so they are called through an object reference.

7. Creating Multiple Objects from One Class

One class can be used to create many objects. Each object can hold its own instance data.

using System;

class Student
{
    public string Name { get; set; }
    public int Marks { get; set; }

    public void DisplayResult()
    {
        Console.WriteLine($"Name: {Name}, Marks: {Marks}");
    }
}

class Program
{
    static void Main()
    {
        Student student1 = new Student
        {
            Name = "Rahul",
            Marks = 85
        };

        Student student2 = new Student
        {
            Name = "Priya",
            Marks = 92
        };

        student1.DisplayResult();
        student2.DisplayResult();
    }
}

Output:

Name: Rahul, Marks: 85
Name: Priya, Marks: 92

Although both objects are instances of Student, each object stores its own Name and Marks values.

Changing student1.Name does not change student2.Name.

8. Object Initializers in C#

An object initializer allows you to assign values to accessible fields or properties when creating an object.

Without an object initializer:

Student student = new Student();

student.Name = "Anjali";
student.Marks = 88;

With an object initializer:

Student student = new Student
{
    Name = "Anjali",
    Marks = 88
};

Both examples create a Student object and assign the specified values. An object initializer makes object setup more concise and readable.

Object initializers do not replace constructors. The constructor runs first, and then the initializer assignments are applied.

9. Constructors in C#

A constructor is a special class member that runs when an instance is created. It is commonly used to initialize an object's state.

A constructor has the same name as the class and does not declare a return type.

class Student
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Student(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Creating an object with this constructor:

Student student = new Student("Rahul", 20);

Console.WriteLine(student.Name);
Console.WriteLine(student.Age);

Output:

Rahul
20

Because the class declares a constructor that requires two arguments, new Student() without arguments will not compile unless a parameterless constructor is also provided.

Constructors can help ensure that objects begin with the information they need. Constructor types, constructor overloading, and related techniques are covered in detail in the next tutorial.

10. Instance Members vs Static Members

A class can contain both instance members and static members.

Instance members

Instance fields, properties, and methods belong to individual objects. Each object has its own instance state.

Static members

Static members belong to the type itself rather than to a particular object. A static member is accessed using the class name.

class Employee
{
    public string Name { get; set; }

    public static string CompanyName = "Param Technologies";

    public void Display()
    {
        Console.WriteLine($"{Name} works at {CompanyName}.");
    }
}

Usage:

Employee employee1 = new Employee { Name = "Amit" };
Employee employee2 = new Employee { Name = "Neha" };

employee1.Display();
employee2.Display();

Console.WriteLine(Employee.CompanyName);

Output:

Amit works at Param Technologies.
Neha works at Param Technologies.
Param Technologies

Name is an instance property, so each employee has a separate value. CompanyName is static, so it is associated with the Employee type.

A static method cannot directly access an instance member without an object reference. Static members are useful for functionality or data that genuinely belongs to the type as a whole.

11. Real-Life Example: A Bank Account Class

A bank account has data, such as its account holder and balance, and behavior, such as depositing or withdrawing money.

This example uses a private balance field and public methods to control updates.

using System;

class BankAccount
{
    public string AccountHolder { get; set; }

    private decimal balance;

    public decimal Balance
    {
        get { return balance; }
    }

    public BankAccount(string accountHolder, decimal initialBalance)
    {
        if (initialBalance < 0)
        {
            throw new ArgumentOutOfRangeException(
                nameof(initialBalance),
                "Initial balance cannot be negative.");
        }

        AccountHolder = accountHolder;
        balance = initialBalance;
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
        {
            Console.WriteLine("Deposit amount must be positive.");
            return;
        }

        balance += amount;
        Console.WriteLine($"Deposited: {amount:C}");
    }

    public void Withdraw(decimal amount)
    {
        if (amount <= 0)
        {
            Console.WriteLine("Withdrawal amount must be positive.");
            return;
        }

        if (amount > balance)
        {
            Console.WriteLine("Insufficient balance.");
            return;
        }

        balance -= amount;
        Console.WriteLine($"Withdrawn: {amount:C}");
    }

    public void DisplayBalance()
    {
        Console.WriteLine($"Account Holder: {AccountHolder}");
        Console.WriteLine($"Current Balance: {Balance:C}");
    }
}

class Program
{
    static void Main()
    {
        BankAccount account =
            new BankAccount("Rahul", 5000m);

        account.Deposit(1500m);
        account.Withdraw(1000m);
        account.DisplayBalance();
    }
}

Example output (currency formatting depends on the system's culture):

Deposited: ₹1,500.00
Withdrawn: ₹1,000.00
Account Holder: Rahul
Current Balance: ₹5,500.00

How this example works

  • BankAccount defines the structure and behavior of a bank account.

  • AccountHolder stores the account holder's name.

  • balance is private, so callers cannot directly assign arbitrary values to it.

  • Balance exposes a read-only view of the current balance.

  • Deposit() increases the balance only when the amount is positive.

  • Withdraw() prevents withdrawals that exceed the available balance.

  • The constructor initializes the account holder and opening balance.

This is a simplified educational example, not a complete banking system. Real financial software requires additional controls, transaction records, concurrency handling, security, and auditing.

12. Working with Objects in a List

When an application needs to manage multiple records, you can store object references in a collection such as List<T>.

using System;
using System.Collections.Generic;

class Student
{
    public string Name { get; set; }
    public int Marks { get; set; }
}

class Program
{
    static void Main()
    {
        List<Student> students = new List<Student>
        {
            new Student { Name = "Rahul", Marks = 85 },
            new Student { Name = "Priya", Marks = 92 },
            new Student { Name = "Amit", Marks = 78 }
        };

        foreach (Student student in students)
        {
            Console.WriteLine(
                $"{student.Name}: {student.Marks}");
        }
    }
}

Output:

Rahul: 85
Priya: 92
Amit: 78

This approach is useful for student records, products, employees, orders, and other collections of related data.

13. Class and Object Reference Behavior

Classes are reference types. A variable of a class type holds a reference to an object rather than containing the complete object value directly.

Consider the following example:

class Student
{
    public string Name { get; set; }
}

class Program
{
    static void Main()
    {
        Student student1 = new Student
        {
            Name = "Rahul"
        };

        Student student2 = student1;

        student2.Name = "Amit";

        Console.WriteLine(student1.Name);
        Console.WriteLine(student2.Name);
    }
}

Output:

Amit
Amit

Both variables refer to the same object. Assigning student1 to student2 does not create a second Student instance.

To create a separate object, instantiate the class again:

Student student1 = new Student { Name = "Rahul" };
Student student2 = new Student { Name = "Amit" };

Now the two variables refer to different objects.

What happens when a class variable is null?

A class variable can contain null, which means it does not currently refer to an object.

Student student = null;

// This would throw NullReferenceException:
// Console.WriteLine(student.Name);

In projects with nullable reference types enabled, the compiler can help identify potentially unsafe null usage. You should check or otherwise establish that a reference points to an object before accessing its members.

14. Common Mistakes When Working with Classes and Objects

Mistake 1: Using an object before creating it

Incorrect:

Student student = null;
student.Name = "Rahul";

This throws a NullReferenceException at runtime.

Correct:

Student student = new Student();
student.Name = "Rahul";

Mistake 2: Confusing the class with the object

Incorrect assumption: declaring class Student creates a student record.

Correct understanding: the declaration defines the type. An instance is created separately, for example, with new Student().

Mistake 3: Assuming two variables always mean two objects

Student first = new Student();
Student second = first;

Both variables refer to the same instance. Use new Student() again when a separate instance is required.

Mistake 4: Making all fields public

Public fields expose internal state directly. Prefer properties and suitable access modifiers so that the class can enforce its rules.

Mistake 5: Forgetting constructor requirements

If a class defines only a constructor with parameters, creating an instance without those parameters will fail to compile.

Mistake 6: Accessing instance members directly from static code

A static method has no implicit current instance. Create or receive an object reference to access its instance members.

15. Best Practices for Classes and Objects in C#

Follow these practices when designing C# classes:

  1. Use meaningful class names. Prefer Student, Product, and BankAccount over vague names such as Data1.

  2. Keep each class focused. A class should have a clear responsibility.

  3. Encapsulate internal state. Use private fields and controlled properties or methods when necessary.

  4. Validate important input. Prevent invalid values from entering an object's state.

  5. Initialize required data. Use constructors or appropriate initialization patterns to establish valid objects.

  6. Use properties for public data access. They allow validation and future implementation changes.

  7. Avoid unnecessary static state. Shared mutable data can make applications harder to test and maintain.

  8. Handle null references carefully. Use nullable reference types and appropriate validation where supported.

  9. Use collections for groups of objects. List<T> is often a convenient choice for a collection that can grow or shrink.

  10. Keep methods readable. Each method should perform a clearly defined operation.

16. Practice Exercises

Try these exercises to reinforce your understanding.

Exercise 1: Create a Student class

Create a Student class with Name, RollNumber, and Marks properties. Add a method that displays the student's details.

Exercise 2: Create a Car class

Create a Car class with Brand, Model, and Year properties. Create three objects and display their information.

Exercise 3: Build a Calculator class

Create a Calculator class with methods for addition, subtraction, multiplication, and division. Handle division by zero appropriately.

Exercise 4: Create a Product class

Create a Product class with a name and price. Ensure that negative prices cannot be assigned through its public API.

Exercise 5: Build a simple employee list

Create an Employee class and store several employee objects in a List<Employee>. Display every employee's name and salary.

Exercise 6: Create a BankAccount class

Add methods for depositing and withdrawing money. Ensure that the balance cannot become negative through the supported operations.

17. Knowledge Check: Quiz

1. What is a class in C#?

A. A loop
B. A blueprint for creating objects
C. A database
D. A namespace only

2. What is an object?

A. An instance of a class
B. A compiler error
C. A return type
D. A comment

3. Which keyword is commonly used to instantiate a class?

A. class
B. static
C. new
D. return

4. What is the purpose of a property?

A. To define a loop
B. To provide controlled access to a value
C. To create a namespace
D. To terminate a method

5. What happens when two class variables reference the same object?

A. Each variable automatically creates a copy
B. They refer to separate objects in every case
C. Changes made through one reference can be visible through the other
D. The program always crashes

Answers: 1-B, 2-A, 3-C, 4-B, 5-C.

18. Frequently Asked Questions (FAQs)

Q1. What is the difference between a class and an object in C#?

A class defines a type and its members. An object is an instance of that class with its own instance state.

Q2. Can I create multiple objects from one class?

Yes. You can create as many instances as needed, subject to available resources and application constraints. Each instance has its own instance fields and properties.

Q3. What is the difference between a field and a property?

A field is a variable declared in a type. A property provides accessors for reading or assigning a value and can include validation or other logic.

Q4. Do I always need to write a constructor?

No. If you do not declare an instance constructor, C# generally provides an implicit parameterless constructor for an ordinary class. If you declare constructors yourself, the available construction options depend on those declarations.

Q5. What is the purpose of the new keyword?

For a class, new is commonly used to create an instance and invoke a constructor. The keyword also has other uses in C#, including target-typed object creation and member hiding in specific contexts.

Q6. What is the difference between static and instance members?

Instance members belong to individual objects. Static members belong to the type itself and are accessed through the type name.

Q7. Can an object exist without a variable that stores its reference?

Yes. An object can be created and passed directly to a method or stored in a collection without assigning it to a separately named local variable. Its lifetime is managed by the .NET garbage collector when it is no longer reachable and eligible for collection.

Q8. Why are classes useful in real-world applications?

Classes group related data and behavior into meaningful types. They help developers model business concepts, organize code, enforce rules, and maintain larger applications.

Conclusion

Classes and objects are fundamental building blocks of C# programming. A class defines a type, while an object is an instance of that type. By combining fields, properties, methods, and constructors, developers can represent real-world entities and build structured applications.

You have learned how to create classes, instantiate objects, work with multiple instances, use object initializers, distinguish static from instance members, and control object state with a practical bank account example.

←
Post 11 of 13
→