7 hours · 9 marks (largest chapter)
A class is a user-defined blueprint that groups data members (attributes) and member functions (methods) into one unit. Declared with the keyword class.
class Student {
private:
int roll;
string name;
public:
void setData(int r, string n) { roll = r; name = n; }
void display() { cout << roll << " " << name; }
};
Access specifiers control visibility: private (accessible only inside the class — default for class), protected (accessible in class and derived classes), public (accessible anywhere the object is visible).
An object is an instance of a class — creating an object allocates memory for its data members.
Student s1; // object creation
s1.setData(1, "Ram"); // member access using dot (.) operator
s1.display();
Student *sp = &s1;
sp->display(); // member access via pointer using ->
this so the function knows which object's data to use.new (heap), and released when it goes out of scope or is deleted.class Box {
int length;
public:
void setLength(int l) { length = l; } // defined inside class -> implicitly inline
};
class Box {
int length;
public:
void setLength(int l); // declaration only
int getLength();
};
void Box::setLength(int l) { length = l; } // :: scope resolution operator
int Box::getLength() { return length; }
Functions defined outside the class using :: are NOT implicitly inline (unless explicitly marked inline), whereas functions defined inside the class body are implicitly treated as inline requests.
A class can contain objects of another class as its data members — this is called composition or a has-a relationship.
class Engine { public: void start() { cout << "Engine started"; } };
class Car {
Engine e; // Engine object as a member of Car
public:
void drive() { e.start(); cout << " Car moving"; }
};
Constructor: a special member function with the same name as the class, automatically invoked when an object is created; used to initialize data members. No return type (not even void).
Destructor: a special member function named ~ClassName(), automatically invoked when an object is destroyed; used to release resources. Takes no arguments, cannot be overloaded, and has no return type.
| Type | Description |
|---|---|
| Default constructor | Takes no arguments; compiler supplies one if none is defined. |
| Parameterized constructor | Takes arguments to initialize members with specific values. |
| Copy constructor | ClassName(const ClassName &obj) — creates a new object as a copy of an existing object. |
class Demo {
int x;
public:
Demo() { x = 0; cout << "Default ctor\n"; } // default
Demo(int a) { x = a; cout << "Param ctor\n"; } // parameterized
Demo(const Demo &d) { x = d.x; cout << "Copy ctor\n"; } // copy
~Demo() { cout << "Destructor\n"; }
};
int main() {
Demo d1; // default ctor
Demo d2(5); // param ctor
Demo d3 = d2; // copy ctor
} // destructors called in reverse order: d3, d2, d1
Objects can be passed to functions by value (a copy is made using the copy constructor), by reference (&, no copy, changes affect original), or by pointer.
void show(Demo d) { } // pass by value -> copy constructor invoked
void show(Demo &d) { } // pass by reference -> no copy
void show(Demo *d) { } // pass by pointer
class Point {
int x, y;
public:
Point(int a=0, int b=0): x(a), y(b) {}
Point add(Point p) { // returns a new Point object by value
return Point(x + p.x, y + p.y);
}
};
When a function returns an object by value, a temporary object is created (often optimized away by the compiler via return value optimization, RVO).
class Student { public: int roll; };
Student s[3]; // array of 3 Student objects, default ctor called 3 times
s[0].roll = 1;
s[1].roll = 2;
Student *p = new Student; // dynamically allocated object
p->roll = 5; // access member via ->
delete p;
Student arr[3];
Student *q = arr; // pointer to first element
(q+1)->roll = 10; // access second element via pointer arithmetic
Student *p = new Student(); // single object on heap
Student *arr = new Student[5]; // array of objects on heap
delete p;
delete[] arr; // must use [] for arrays
A constructor that allocates memory dynamically (using new) for a data member at object-creation time — commonly used when the size of a member (e.g., a string or array) is not known until run time.
class Str {
char *data;
public:
Str(const char *s) {
data = new char[strlen(s) + 1]; // dynamic allocation inside constructor
strcpy(data, s);
}
~Str() { delete[] data; } // must free in destructor
};
Classes with dynamic constructors must also define a proper copy constructor and destructor (the "Rule of Three") to avoid shallow-copy bugs (two objects pointing to and freeing the same memory).
this pointer)Every non-static member function has an implicit parameter called this — a pointer to the object that invoked the function. Used to resolve naming conflicts between a parameter and a data member, and to return the current object (e.g., for chaining).
class Box {
int length;
public:
Box &setLength(int length) {
this->length = length; // 'this->length' is the member, 'length' is the parameter
return *this; // enables chaining: obj.setLength(1).setLength(2);
}
};
Static data member: shared by all objects of the class — only one copy exists regardless of how many objects are created. Must be defined (given storage) outside the class.
Static member function: can be called without an object (using the class name), and can only access other static members directly (it has no this pointer).
class Counter {
static int count; // declaration
public:
Counter() { count++; }
static int getCount() { return count; } // static function
};
int Counter::count = 0; // definition + initialization (outside class)
int main() {
Counter a, b, c;
cout << Counter::getCount(); // 3 -- called using class name
}
class Box {
int length;
public:
int getLength() const { return length; } // const member function: cannot modify data members
};
const Box b; // constant object: can only call const member functions on it
// b.getLength(); -> OK
// b.setLength(5); -> error if setLength is non-const
A const member function guarantees it will not modify the object's data members (except members marked mutable). A const object can only invoke const member functions.
A friend function is a non-member function granted access to a class's private and protected members. A friend class grants all member functions of another class the same access.
class Box {
int length;
public:
Box(int l): length(l) {}
friend void printLength(Box b); // friend declaration inside class
};
void printLength(Box b) { // NOT a member function, but can access b.length
cout << b.length;
}
class B; // forward declaration
class A {
friend class B; // B can access A's private members
int secret = 42;
};
class B {
public:
void reveal(A a) { cout << a.secret; }
};
Friendship is not mutual and not inherited: if A declares B as a friend, B does not automatically consider A a friend, and derived classes of B do not automatically gain the friendship either.
Rectangle with member functions to set dimensions and calculate area. 6 marksclass Rectangle {
float length, width;
public:
void setDimension(float l, float w) { length = l; width = w; }
float area() { return length * width; }
};
int main() {
Rectangle r;
r.setDimension(4, 5);
cout << r.area(); // 20
}
this pointer? Explain its uses with an example. 4 marksthis is an implicit pointer available inside every non-static member function, pointing to the calling object. Uses: (1) disambiguate a data member from a parameter of the same name, (2) return the current object by reference to support method chaining, (3) pass the current object to another function. See code in section 3.14.friend keyword.
class ClassB;
class ClassA {
int a = 10;
public:
friend int addValues(ClassA, ClassB);
};
class ClassB {
int b = 20;
public:
friend int addValues(ClassA, ClassB);
};
int addValues(ClassA x, ClassB y) { return x.a + y.b; }
int main() { cout << addValues(ClassA(), ClassB()); } // 30
new, useful when the required size is unknown at compile time (e.g., a variable-length string). See the Str class example in section 3.13; explain why the destructor must free this memory and why a proper copy constructor is also required to prevent two objects sharing (and both freeing) the same memory block.const after its parameter list guarantees that it will not modify any data member of the object (except mutable members). They are needed so that const objects (and references/pointers to const objects) can still call safe, read-only methods — without const member functions, a const object could call no member functions at all. See section 3.16.class Student {
int roll; string name;
public:
void set(int r, string n) { roll = r; name = n; }
void show() { cout << roll << " " << name << endl; }
};
int main() {
Student s[3];
s[0].set(1, "Ram"); s[1].set(2, "Shyam"); s[2].set(3, "Hari");
for (int i = 0; i < 3; i++) s[i].show();
}
this pointer per object).