Thursday, January 19, 2012

Explicit Constructor C++

The C++ is designed in such a way that by default,a single argument constructor also defines an implicit conversion. In C++, an implicit conversion is a conversion from one type to another that doesn't require an explicit typecast. For example consider following class:

class Conversion {
public:
    Conversion(int o=0) : data(o) {    }
    int getData() { return data;}
private:
    int data;
};

int main(){
  Conversion c = 5;   // initialize c with Conversion(5)
  cout << c.getData() << endl;
  return 0;
}


Here the constructor worked as implicit converter. 
But there are cases where this feature can play bad. Consider following: 
 
class MyString {
public:
    MyString(const char* str);        // initial val is c-style string  str 
    MyString(const int len=0);        // pre-allocate len bytes
    const char* getData() const { return c;}
private:
    char *c;
    unsigned int len;
};
MyString::MyString(const int len) {
   this->len=len;
    c= new char[len+1];
}
MyString::MyString(const char *str) {
    len = strlen(str);
    c = new char[len+1];
    strcpy(c, str);
}
int main()
{
  MyString m_str = "it works here"; //MyString(const char *str)
  cout << m_str.getData()<< endl;
  MyString m_str2 = 'a';            //MyString(const int len)
  cout << m_str2.getData() << endl;
  return 0;
} 

Now, MyString m_str2 = 'a'; makes m_str2 a string with 'a' char, its quite unlikely 
that this is what person want. So make sure that the conversion is intuitive and
consistent with major C++ conventions. If not, consider using non-constructor member functions.

To prevent above discussed problem C++ comes up with explicit keyword, that suppressed the implicit conversion. That is, an explicit constructor will be invoked only explicitly. So if we modify above class declaration as follow:

class MyString {
public:
    MyString(const char* str);        // initial val is c-style string  str 
    explicit MyString(const int len=0);        // pre-allocate len bytes
    const char* getData() const { return c;}
private:
    char *c;
    unsigned int len;
};

Now for line
    MyString m_str2 = 'a';    

We will get compiler error since there's no implicit conversion from char to int. How ever we can still write
    MyString m_str2(10); 
Which is what we were trying to accomplish in the first place.
 
When designing classes, if you have a single-argument constructor that is not intended
 as a conversion function, you must mark it explicit to avoid running into the “implicit conversion” trap. 






No comments:

Post a Comment