Function overloading allows multiple functions with the same name but different parameters to exist in the same scope. This is a feature of C++ and some other statically-typed languages.
Function overloading is not possible in C. However, it can be somewhat emulated using variable arguments. The printf
function is a classic example:
int printf(const char *format, ...);
Python variables are dynamically typed, which means a single function can handle multiple types:
def foo(param):
if isinstance(param, int):
# Do something with int param
return int_result
elif isinstance(param, float):
# Do something with float param
return float_result
elif isinstance(param, str):
# Do something with string param
return str_result
Since C++ is statically typed, multiple functions need to be written to handle different types:
// Compiler will call this one if foo has an int argument
int foo(int param){
// Do something with int param
return int_result;
}
// Compiler will call this one if foo has a float argument
float foo(float param){
// Do something with float param
return float_result;
}
In C++, classes are similar to structs, but with different default access levels for members.
C++ provides three access specifiers:
struct Name{
int PubDataMember; // Default is public
private: // All members are private after
int PrivDataMember;
protected: // Now all are protected after
int ProtDataMember;
public: // Now all are public again after
int OthPubDataMember;
};
class OtherName{
int PrivDataMember; // Default is private
public: // All members are public after
int PubDataMember;
protected: // Now all are protected after
int ProtDataMember;
private: // Now all are private again after
int OthPrivDataMember;
};
Destructors are member functions that are called when an object is destroyed. They are useful for cleanup tasks.
// Typically in header file
class Name{
public:
Name(); // Constructor
~Name(); // Destructor
};
// Typically in cpp file
Name::Name(){
std::cout << "Name constructor" << std::endl;
}
Name::~Name(){
std::cout << "Name destructor" << std::endl;
}
// Typically in another cpp file
{
std::cout << "Start" << std::endl;
Name Object; // Constructor called here
} // Object goes out of scope and destructor called
std::cout << "End" << std::endl;
// Output of above code
// Start
// Name constructor
// Name destructor
// End
Inheritance allows a class or struct to be derived from another, enabling code reuse and polymorphism.
class Base:
def __init__(self, param):
self.DataMember = param
class Derived(Base):
def __init__(self, param, param2):
Base.__init__(self, param)
self.DataMember2 = param2
// Typically in header file
struct Base{
int DataMember;
Base(int param); // Constructor
};
struct Derived : Base{
int DataMember2;
Derived(int param, int param2); // Constructor
};
// Typically in cpp file
Base::Base(int param){
DataMember = param;
}
Derived::Derived(int param, int param2) : Base(param){
DataMember2 = param2;
}
Function overriding allows a derived class to provide a specific implementation of a function that is already defined in its base class.
// Typically in header file
struct Base{
virtual void foo(int param);
};
struct Derived : Base{
void foo(int param) override;
};
// Typically in cpp file
void Base::foo(int param){
std::cout << "Base " << param << std::endl;
}
void Derived::foo(int param){
std::cout << "Derived " << param << std::endl;
}
// Typically in another cpp file
Derived Object;
Base *Ptr = &Object; // Point to Object
Object.foo(3); // Calls overridden function
Ptr->foo(4); // Calls function of object type
// Output of above code
// Derived 3
// Derived 4
Interfaces define the allowed interaction and expected behavior, but not the implementation. In C++, abstract classes are used for interfaces.
// Typically in header file
class Logger{
public:
virtual ~Logger(){}; // Good practice
virtual void log(const std::string &mes) = 0;
};
// Typically in another header file
class StdLogger : public Logger{
public:
void log(const std::string &mes) override;
};
// Typically in yet another header file
class FileLogger : public Logger{
std::ofstream DFile;
public:
FileLogger(const std::string &filename);
void log(const std::string &mes) override;
};
// Typically in cpp file
void StdLogger::log(const std::string &mes){
std::cout << mes << std::endl;
}
// Typically in another cpp file
FileLogger::FileLogger(const std::string &filename) : DFile(filename){}
void FileLogger::log(const std::string &mes){
DFile << mes << std::endl;
}
// Typically in yet another cpp file
void foo(Logger *logger){
logger->log("A message");
}
add
that handle int
, float
, and double
types.
class Base {
public:
virtual void show() { std::cout << "Base class" << std::endl; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived class" << std::endl; }
};
int main() {
Base *b;
Derived d;
b = &d;
b->show();
return 0;
}
Shape
with a virtual function area()
. Derive two classes Circle
and Rectangle
from Shape
and override the area()
function. Demonstrate polymorphism by calling the area()
function using a pointer to Shape
.