About static and virtual keyword
About static
The static keyword can be used to declare variables, functions, class data members and class functions.
By default, an object or variable that is defined outside all blocks has static duration and external linkage. Static duration means that the object or variable is allocated when the program starts and is deallocated when the program ends. External linkage means that the name of the variable is visible from outside the file in which the variable is declared. Conversely, internal linkage means that the name is not visible outside the file in which the variable is declared.
The static keyword can be used in the following situations.
- When we declare a variable or function at file scope (global and/or namespace scope), the static keyword specifies that the variable or function has internal linkage. When we declare a variable, the variable has static duration and the compiler initializes it to 0 unless we specify another value.
- When we declare a variable in a function, the static keyword specifies that the variable retains its state between calls to that function.
- When we declare a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all instances of the class. A static data member must be defined at file scope. An integral data member that we declare as const static can have an initializer.
- When we declare a member function in a class declaration, the static keyword specifies that the function is shared by all instances of the class. A static member function cannot access an instance member because the function does not have an implicit this pointer. To access an instance member, declare the function with a parameter that is an instance pointer or reference.
static member functions are considered to have class scope. In contrast to nonstatic member functions, these functions have no implicit this argument; therefore, they can use only static data members, enumerators, or nested types directly. Static member functions can be accessed without using an object of the corresponding class type. Consider this example:
// static_member_functions.cpp
#include <stdio.h>
class StaticTest
{
private:
static int x;
public: static int count()
{
return x;
}
};
int StaticTest::x = 9;
int main()
{
printf_s("%d\n", StaticTest::count());
return 0;
}
In the preceding code, the class StaticTest contains the static member function count. This function returns the value of the private class member but is not necessarily associated with a given object of type StaticTest.
Static member functions have external linkage.
- They cannot access nonstatic class member data using the member-selection operators (. or >).
- They cannot have the same name as a nonstatic function that has the same argument types.
- They cannot be declared as virtual.
Virtual Functions
In C++ we achieve polymorphism by using virtual keyword.
A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.
Virtual functions ensure that the correct function is called for an object, regardless of the expression used to make the function call.
Suppose a base class contains a function declared as virtual and a derived class defines the same function. The function from the derived class is invoked for objects of the derived class, even if it is called using a pointer or reference to the base class. The following example shows a base class that provides an implementation of the PrintBalance function and two derived classes.
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream.h>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for base type." << endl; }
private:
double _balance;
};
class CheckingAccount : public Account {
public:
CheckingAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Checking account balance: " << GetBalance() << endl; }
};
class SavingsAccount : public Account {
public:
SavingsAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Savings account balance: " << GetBalance(); }
};
int main() {
// Create objects of type CheckingAccount and SavingsAccount.
CheckingAccount *pChecking = new CheckingAccount( 100.00 ) ;
SavingsAccount *pSavings = new SavingsAccount( 1000.00 );
// Call PrintBalance using a pointer to Account.
Account *pAccount = pChecking;
pAccount->PrintBalance();
// Call PrintBalance using a pointer to Account.
pAccount = pSavings;
pAccount->PrintBalance();
return 0;
}
In the preceding code, the calls to PrintBalance are identical, except for the object pAccount points to. Because PrintBalance is virtual, the version of the function defined for each object is called. The PrintBalance function in the derived classes CheckingAccount and SavingsAccount "override" the function in the base class Account.
If a class is declared that does not provide an overriding implementation of the PrintBalance function, the default implementation from the base class Account is used.
Virtual Base Classes
Because a class can be an indirect base class to a derived class more than once, C++ provides a way to optimize the way such base classes work. Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritance.
Each nonvirtual object contains a copy of the data members defined in the base class. This duplication wastes space and requires you to specify which copy of the base class members you want whenever you access them.
When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members. A single copy of its data members is shared by all the base classes that use it as a virtual base.
Pure virtual functions
In C++, virtual functions let instances of related classes have different behavior at run time (aka, runtime polymorphism) :
class Shape
{
public:
virtual double area() const;
double value() const;
virtual ~Shape();
protected:
Shape(double valuePerSquareUnit);
private:
double valuePerSquareUnit_;
};
class Rectangle : public Shape {
public:
Rectangle(double width, double height, double valuePerSquareUnit);
virtual double area() const;
virtual ~Rectangle();
// ...
};
class Circle : public Shape {
public:
Circle(double radius, double valuePerSquareUnit);
virtual double area() const;
virtual ~Circle();
// ...
};
double Shape::value() const
{
// Area is computed differently, depending
// on what kind of shape the object is:
return valuePerSquareUnit_ * area();
}
In C++, a function's interface is specified by declaring the function. Member functions are declared in the class definition. A function's implementation is specified by defining the function. Derived classes can redefine a function, specifying an implementation particular to that derived class (and classes derived from it). When a virtual function is called, the implementation is chosen based not on the static type of the pointer or reference, but on the type of the object being pointed to, which can vary at run time:
print(shape->area()); // Might invoke Circle::area() or Rectangle::area().
A pure virtual function is declared, but not necessarily defined, by a base class. A class with a pure virtual function is "abstract" (as opposed to "concrete"), in that it's not possible to create instances of that class. A derived class must define all inherited pure virtual functions of its base classes to be concrete.
class AbstractShape {
public:
virtual double area() const = 0;
double value() const;
virtual ~AbstractShape();
protected:
AbstractShape(double valuePerSquareUnit);
private:
double valuePerSquareUnit_;
protected:
AbstractShape(double valuePerSquareUnit);
private:
double valuePerSquareUnit_;
};
// Circle and Rectangle are derived from AbstractShape.
// This will not compile, even if there's a matching public constructor:
// AbstractShape* p = new AbstractShape(value);
// These are okay:
Rectangle* pr = new Rectangle(height, weight, value);
Circle* pc = new Circle(radius, value);
// These are okay, too:
AbstractShape* p = pr;
p = pc;
How does all this run time magic happen? The usual implementation is, every class with any virtual functions has an array of function pointers, called a "vtbl". Every instance of such as class has a pointer to its class's vtbl, as depicted below.


Virtual destructor
When we make an instances of derived class then the base classes are constructed first. That means first the constructor of base class is called and after that derived class constructor is called.
When we delete the object first the derived class destructor is called and after that base class destructor is called. This is fine no problem.
When we express derive class as a pointer to base class then we have problem. See case 2 in the following example. If you run this example then you notice that Derived class's destructor is not called, thus giving you a memory leak. This can be avoided if we declare the Base class destructor as virtual. Now if you declare ~Base() as virtual ~Base() then notice that derived class destructor is called and no memory leak occurs.
#include <iostream.h>
class Base
{
public:
Base()
{
pibase = new int;
*pibase = 10;
}
~Base()
{
delete pibase;
cout << "~Base destructor called\n ";
}
int *pibase;
};
class Derived : public Base
{
public:
Derived()
{
piderived = new int;
*piderived = 30;
}
~Derived()
{
delete piderived;
cout << "~Derived destructor called\n ";
}
int *piderived;
};
int main()
{
// case 1
Derived* ptr2 = new Derived();
delete ptr2;
// case 2
Base* ptr = new Derived();
delete ptr;
// Since the Base destructor is not virtual,
//the derived Destructor will not be called.
return 0;
}
