Instance members
Instance members in a C++ class are elements (variables or functions) that belong to instances of the class, rather than to the class itself. Each object (instance) of the class has its own separate copy of these members. There are two main types of instance members in a C++ class:
Instance Variables (Non-static Data Members): These are the variables defined in a class that are not declared as static
. Each object of the class will have its own copy of these variables. They represent the state of an object.
Instance Methods (Non-static Member Functions): These are the functions defined in a class that are not declared as static
. These methods operate on the instance variables of the object that invokes them.
Here’s an example to illustrate instance members in a C++ class:
class Car {
private:
// Instance variable
int speed;
public:
// Constructor
Car() : speed(0) {}
// Instance method
void accelerate(int increment) {
speed += increment;
}
// Another instance method
int getSpeed() const {
return speed;
}
};
int main() {
Car myCar; // Creating an object of Car
myCar.accelerate(10); // Calling an instance method
int currentSpeed = myCar.getSpeed(); // Using another instance method
return 0;
}
In this example, speed
is an instance variable, and accelerate
and getSpeed
are instance methods of the Car
class. Each Car
object will have its own speed
, and the methods accelerate
and getSpeed
will operate on the speed
of the Car
object that calls them.
Class Members (Static)
Class members in C++ that are declared as static
belong to the class itself, rather than to any particular instance of the class. This means that they are shared among all instances of the class. Static members can include both variables and functions.
Here are the key points about static members in C++:
Static Variables (Class Variables): These are variables declared with the static
keyword within a class. They are shared by all objects of the class. All instances of the class access the same static variable, and any changes made to the variable are reflected across all instances.
Static Methods (Class Methods): These are functions declared as static
within a class. They can be called without creating an instance of the class. Static methods can only access static variables or other static methods; they cannot access non-static members of the class.
Here’s an example to illustrate static members in a C++ class:
#include <iostream>
class Car {
private:
static int totalCars; // Static variable
public:
// Constructor
Car() {
totalCars++; // Increment total cars
}
// Static method
static int getTotalCars() {
return totalCars;
}
};
// Initialize the static member
int Car::totalCars = 0;
int main() {
Car car1; // First instance of Car
Car car2; // Second instance of Car
// Access static method
std::cout << "Total cars: " << Car::getTotalCars() << std::endl;
return 0;
}
Virtual Functions
Virtual functions in C++ are a fundamental concept for achieving runtime polymorphism. They allow a function in a base class to be overridden in a derived class, enabling dynamic method binding.
Definition: A virtual function is a function in a base class that is declared using the keyword virtual
. When a function is marked as virtual, it can be overridden in any derived class. The version of the function that gets executed is determined at runtime based on the type of the object that invokes the function.
Runtime Polymorphism
- How It Works: When you have a pointer or a reference to a base class object, it can point to objects of the derived class as well. Calling a virtual function through this pointer or reference will execute the function defined in the derived class, if it is overridden there.
Example:
Consider an example with a base class Animal
and derived classes Dog
and Cat
:
#include <iostream>
using namespace std;
class Animal {
public:
// Virtual function
virtual void speak() {
cout << "Some animal sound" << endl;
}
};
class Dog : public Animal {
public:
// Overriding the virtual function
void speak() override {
cout << "Woof Woof" << endl;
}
};
class Cat : public Animal {
public:
// Overriding the virtual function
void speak() override {
cout << "Meow Meow" << endl;
}
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->speak(); // Outputs: Woof Woof
animal2->speak(); // Outputs: Meow Meow
delete animal1; // Clean up
delete animal2; // Clean up
return 0;
}
In this example:
Animal
has a virtual functionspeak()
.Dog
andCat
override this function.- When
speak()
is called on anAnimal
pointer that points to aDog
orCat
object, the corresponding overridden function in theDog
orCat
class is executed. - This demonstrates runtime polymorphism: the decision about which function to execute is made at runtime based on the actual type of the object that the
Animal
pointer is referring to.
Key Points
- Virtual functions enable runtime polymorphism, allowing different behaviors for objects of derived classes when accessed through a base class reference or pointer.
- The virtual function mechanism is central to achieving dynamic method binding in C++, which is the ability to decide which function to invoke at runtime rather than at compile time.
Pure Virtual Functions
Definition: A pure virtual function is a function that is declared in a base class but must be implemented in a derived class. It is declared by assigning 0
to the function declaration in the base class. Pure virtual functions are used to create abstract classes in C++, which are classes that cannot be instantiated directly and are meant to be inherited.
Purpose
- Creating Abstract Base Classes: Pure virtual functions are used to define an interface in the base class. Any class that inherits from this base class must provide an implementation for these functions, ensuring a consistent interface across derived classes.
- Ensuring Implementation in Derived Classes: They are essential for scenarios where the base class cannot provide a meaningful implementation for a function, and the implementation must be provided by the derived classes.
Example:
#include <iostream>
using namespace std;
class Shape {
public:
// Pure virtual function
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing Circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing Rectangle" << endl;
}
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Rectangle();
shape1->draw(); // Outputs: Drawing Circle
shape2->draw(); // Outputs: Drawing Rectangle
delete shape1; // Clean up
delete shape2; // Clean up
return 0;
}
In this example:
Shape
is an abstract base class with a pure virtual functiondraw()
.Circle
andRectangle
are derived classes that provide specific implementations of thedraw()
function.
Differences between Virtual Functions and Pure Virtual Functions
- Default Implementation:
- Virtual Function: Can have a default implementation in the base class. It’s optional for the derived class to override it.
- Pure Virtual Function: Does not have a default implementation in the base class. It must be overridden by the derived class.
- Abstract Class Creation:
- Virtual Function: The presence of a virtual function does not make a class abstract. The class can still be instantiated.
- Pure Virtual Function: If a class has at least one pure virtual function, it becomes an abstract class and cannot be instantiated.
- Use Case:
- Virtual Function: Used when the base class has a default behavior that can be shared or overridden by derived classes.
- Pure Virtual Function: Used when the base class defines only an interface, and the actual implementation is mandatory in each derived class.
In summary, while virtual functions allow derived classes to override a method, pure virtual functions require it, making them a key tool in defining abstract interfaces in C++.
Abstract Classes
Definition
An abstract class in C++ is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. It represents a high-level concept that cannot be instantiated on its own.
Characteristics
- Cannot Be Instantiated: You cannot create objects of an abstract class.
- Intended for Inheritance: Abstract classes are intended to be inherited by concrete classes that implement the pure virtual functions.
- Defines Interface: They are often used to define an interface for other classes to follow.
Purpose
- Enforcing a Contract for Derived Classes: By declaring at least one pure virtual function, an abstract class ensures that any derived class must implement these functions, providing a consistent interface.
- Code Reusability: Abstract classes can also contain normal (non-pure) virtual functions with implementation, promoting code reuse.
Example:
Scenario:
We want to model a system where different types of vehicles can be represented. All vehicles should have a method to start, but the specific way they start depends on the type of vehicle.
#include <iostream>
using namespace std;
// Abstract class
class Vehicle {
public:
// Pure virtual function
virtual void startEngine() = 0;
// A normal member function with implementation
void honk() {
cout << "Honk! Honk!" << endl;
}
};
class Car : public Vehicle {
public:
void startEngine() override {
cout << "Car engine started" << endl;
}
};
class Boat : public Vehicle {
public:
void startEngine() override {
cout << "Boat engine started" << endl;
}
};
class Bicycle : public Vehicle {
public:
void startEngine() override {
cout << "Bicycle has no engine!" << endl;
}
};
int main() {
// Vehicle v; // Error: Cannot instantiate an abstract class
Vehicle* car = new Car();
Vehicle* boat = new Boat();
Vehicle* bicycle = new Bicycle();
car->startEngine(); // Outputs: Car engine started
boat->startEngine(); // Outputs: Boat engine started
bicycle->startEngine(); // Outputs: Bicycle has no engine!
car->honk(); // Outputs: Honk! Honk!
boat->honk(); // Outputs: Honk! Honk!
bicycle->honk(); // Outputs: Honk! Honk!
delete car; // Clean up
delete boat; // Clean up
delete bicycle; // Clean up
return 0;
}
In this example:
Vehicle
is an abstract class with a pure virtual functionstartEngine()
.Car
,Boat
, andBicycle
are derived classes that provide specific implementations ofstartEngine()
.- The
honk()
method is a regular member function ofVehicle
, which can be used by all derived classes. - We cannot instantiate
Vehicle
directly, as demonstrated by the commented line, but we can instantiateCar
,Boat
, andBicycle
and call bothstartEngine()
andhonk()
on them.
Key Points
- This example demonstrates how an abstract class can be used to define a common interface (
startEngine()
) for various derived classes. - It also shows how abstract classes can contain non-pure virtual functions (
honk()
) that provide default behavior. - The abstract class
Vehicle
serves as a blueprint for creating specific types of vehicles with their unique engine start behaviors, while also sharing common functionality likehonk()
.