Friday, July 27, 2007

typedef name as identifier of constructor/destructor

Description: As per the C++98 a constructor declarator can be a typedef name if the declaration is inside class member specification. It must not be allowed if the declaration is done outside the class member specification.

But the both GCC and VC++ differs in the behaviour. VC++ have correct implementation compared to gcc 3.4.2. Consider the following example,

Example:

class Alpha;
typedef Alpha Constructor;

class Alpha
{
public:
Constructor::Constructor(){}
};

int main()
{
Alpha obj;
}
Explanation:

If you compile the above program using VC++ it will be getting compiled. But if you use the gcc 3.4.2 it will not compile.

I think it is a mistake with GCC because they did not take care of this point in the ISOC++98 standard. And it may be an implementation artifact of Visual C++ that gets this code compiled.

Friday, July 20, 2007

Calling a virtual function of a class from its constructor/destructor

Description:

As you know the construction is done from base to derived and destruction just opposite you should avoid calling a virtual funciton from both constructor and destructor. When you call the virtual function from constructor the derived class is not yet constructed and if from destructor the derived class is already destructed. Hence compiler will make an arrangement so that the local class(ie Base class) virtual function itself is called.

If you call a pure virtual function from your constructor/destructor directly or indirectly the program will be ill-formed. It can either show a compile time error or else a runtime error "Pure virtual function called"(normaly runtime error occures in case of indirect call from constructor ie calling a local non virtual member function and from that member function a call to pure virtual function ).

Example 1

class Base
{
public:
Base()
{
CallPureVirtual(); // Calling pure virtual indirectly from constructor // LINE 6
}
private:
virtual void PureVirtual() = 0;
void CallPureVirtual(){ PureVirtual(); };
};

class Derived : public Base
{
public:
Derived()
{
}
void PureVirtual()
{
std::cout << "Derived::PureVirtual()" << std::endl;
}
};

int main()
{
Derived obj;
return 0;
}


Output and explanation
If the above program is compiled using gcc/VC++2005/VC6 it will definitly give a runtime error. Because a pure virtual function is called.

Example 2

class Base
{
public:
Base()
{
std::cout << "From Base Constructor" << std::endl;
VirtualFun();
}
~Base()
{
std::cout << "From Base Destructor" << std::endl;
VirtualFun();
}
void CallVirtual()
{
std::cout << "From Base CallVirtual" << std::endl;
VirtualFun();
}
private:
virtual void VirtualFun()
{
std::cout << "Base::VirtualFun()" << std::endl;
}
};

class Derived : public Base
{
public:
Derived()
{
}
void VirtualFun()
{
std::cout << "Derived::PureVirtual()" << std::endl;
}
};

int main()
{
Derived obj;
obj.CallVirtual();
return 0;
}

Output and explanation
The above program will output,

From Base Constructor
Base::VirtualFun()
From Base CallVirtual
Derived::PureVirtual()
From Base Destructor
Base::VirtualFun()


Here we can find that from the constructor and destructor of base class the local virtual function is getting called and in other cases the virtual function of the appropriate object is called.

So it is not that you cant call a virtual function from a constructor or destructor, but it may not get you what you desired.

Friday, July 6, 2007

Making a class non derivable / Disabling Inheritability of a class

Description: Have you ever thought how to make a class non-derivable in C++? Your can do it by making use of the rule "The most derived class calls the constructor/destructor of virtual base class".

At first to understand it we should analyze how we solved the diamond inheritance problem. For that we used the concept of virtual base class and inheriting the intermediate class virtually. And then the most derived class (The class of that the object is created, the most bottom one in diamond pattern) calls the constructor/destructor of the virtual base class. So this is the feature that we can use for making a class non derivable.

Code snippet: Here the class NonDerivable is a class from which you cant derive any other class.

class NonDerivable; /* This is just a forward declaration of class that need to be made non derivable*/

class DisableDerive /* A base class */
{
private:
DisableDerive(){}; /* Made the constructor as private*/
friend class NonDerivable; /* Made NonDerivable as friend so that it can access private constructor*/
};
class NonDerivable: virtual public DisableDerive /* Intermediate class - Virtual base*/
{
private:
int m_nVal;
public:
NonDerivable(){ m_nVal = -1;};
void SetValue( int nVal ){ m_nVal = 10; }
};

class TryDerive: public NonDerivable /* Deriving from non derivable class*/
{
};

int main(int argc, _TCHAR* argv[])
{
TryDerive Alpha; /* This will cause compile error because TryDerive cant call constructor of DisableDerive.*/
}


Here the TryDerive tries to derive from NonDerivable. So TryDerive is the most derived class. Hence the constructor of virtual base class DisableDerive will have to be called by TryDerive. But TryDerive cannot access the constructor of DisableDerive since it is private. Hence it will create a compile time error.

Error: error C2248: 'DisableDerive::DisableDerive' : cannot access private member declared in class 'DisableDerive'

But you can of course create the object of class NonDerivable.

And if you just change the line, class NonDerivable: virtual public DisableDerive to class NonDerivable: public DisableDerive, you can derive from the class NonDerivable because the constructor will be called by NonDerivable which is a friend of DisableDerive (It happens because the next derived class calls the constructor).

Microsoft VC++ 2005 Compiler Bug #2

During a friend class specification the compiler is accepting a typedef name. ISOIEC14882-1998 section 9.1 point 5 states that a "typedef-name that names a class is a class-name, but shall not be used in an elaborated-type-specifier". Sections regarding typedef and friend also defines the same. So this usage must raise a compile time error. Instead the vc++2005 compiler accepts the program and successfully compiles it.

Program 1:

#include "stdafx.h"
#include
using namespace std;

class Alpha;
typedef Alpha Constructor ;

class Beta
{
public:
Beta(){;}
private:
int nVal;
friend class Constructor;
};

class Alpha
{
private:
public:
Alpha() {;}
};

int main()
{
Alpha obj1;
Beta obj2;
return 0;
}

Again if the private data of class Beta is accessed by class data, a compile time error is generated regarding access of private data. Here also error must be usage of typedef name in a place where elaborated-type-specifier must be used. Program 2 given below demonstrates this issue.

Program 2
using namespace std;

class Alpha;
typedef Alpha Constructor ;

class Beta
{
private:
int nVal;
friend class Constructor;
};

class Alpha
{
private:
Beta obj;
public:
Alpha::Alpha()
{
obj.nVal = 10;
cout<<"Constructor\n";
}
};

int main()
{
Alpha obj1;
return 0;
}

Microsoft Comment

Thanks for your feedback. We have tried to reproduce the issue with the latest Visual Studio build (Orcas Beta 1) (http://www.microsoft.com/downloads/details.aspx?FamilyId=36B6609E-6F3D-40F4-8C7D-AD111679D8DC&displaylang=en) and we cannot reproduce it. It is likely a known issue fixed in the latest build. If the issue is critical to you with the release of Visual Studio you are working with, you may contact our Product Support Services (http://support.microsoft.com). Our dedicated Support Engineer will work with you to investigate to issue further.

Microsoft VC++ 2005 Compiler Bug #1

It seems like there is implementation difference from ISOIEC14882-1998 rules regarding multiple inheritance and private access specifier.
The private virtual base destructor is accessible from most derived class. No compile time error and no runtime error for program.

class DisableDerive
{
public:
DisableDerive(){ ; }

private:
~DisableDerive(){ ; }
friend class NonDerivable;
};

class NonDerivable: virtual protected DisableDerive
{
private:
int m_nVal;
public:
NonDerivable()
{
std::cout<<"NonDerivable::NonDerivable()\n";
m_nVal = -1;
}
~NonDerivable()
{
std::cout<<"NonDerivable::~NonDerivable()\n";
}
void SetValue( int nVal ){ m_nVal = 10; }
};

class TryDerive: public NonDerivable
{
public:
TryDerive(){ ; }
~TryDerive(){ ; }
};

int main()
{
TryDerive a;
return 0;
}


This code is getting compiled and executed. But there must be an error because the DisableDerive::~DisableDerive must not be accessible from TryDerive. The constructor is not accessible and the problem is only with destructor.

This code is giving expected compile time error in Visual Studio 6.0.

Microsoft Comments on this bug

Thanks for your feedback. We have reproduced this bug on Win2003 SP2 and OrcasBeta1VSTS, and we are sending this bug to the appropriate group within the Visual Studio Product Team for triage and resolution. Thank you, Visual Studio Product Team.
Posted by Microsoft on 6/26/2007 at 8:24 PM

Virtual destruction, delete() and delete[]

Pre-Information
Q. Why base class destructor must be virtual?

A. A base class destructor must be virtual. The reason is if the derived class object is deleted using a base class pointer, the program will be ill-formed( Base class destructor may only be called ), if base class destructor is not virtual.

Tip:
The above rule will only make the program correct if we are NOT deleting the array of objects( ie delete[] ). If we use it the program may be ill-formed.

Example:
struct Base
{
virtual ~Base(){ cout << "~Base()" << endl; }
void operator delete[](void* pObj, size_t){ cout << "Base::delete[] operator" << endl;
::delete [] pObj; }
void operator delete(void* pObj ){ cout << "Base::delete() operator" << endl;
::delete pObj; }
};

struct Derived : Base
{
~Derived(){ cout << "~Derived()" << endl; }
void operator delete[](void* pObj, size_t){ cout << "Derived::operator delete[]" << endl;
::delete [] pObj; }
void operator delete(void* pObj ) { cout << "Derived::operator delete()" << endl;
::delete pObj; }
};

int main()
{
cout << "Creating one derived class object"< Base* pBase = new Derived;
delete pBase; // Deleting a derived class object with base class pointer
cout << "Creating array of derrived class objects";
Base* BasePointer = new Derived[3];
delete[] BasePointer; // Deleting array of derived class objects with base class pointer
getch();
}

In the above program the delete pBase guarantees the proper deallocation of the memory. But the delete[] BasePointer is not assured to be working. The usage of delete[] BasePointer may make the program ill-formed.

If you run the above program it will output:

Creating one derived class object
~Derived()
~Base()
Derived::operator delete()
Creating array of derrived class objects~Derived()
~Base()
~Derived()
~Base()
~Derived()
~Base()
Base::delete[]

The derived class object is deallocated using base class's deallocation function.
This usage is strictly disallowed by C++98 standards.