[ Pobierz całość w formacie PDF ]

virtual ~CommonRoot ();
};
class Derived: public CommonRoot
{
public:
Derived();
};
int main()
{
Derived d; // OK, constructor of d has access to
//any protected member in its base class
CommonRoot cr; //compilation error: attempt to
//access a protected member of CommonRoot
}
The same effect of blocking instantiation of a class can be achieved by declaring pure
virtual functions. However, these add runtime and space overhead. When pure virtual
functions aren't needed, you can use a protected constructor instead.
Using Member Initialization Lists
A constructor might have a member initialization (mem-initialization for short) list that
initializes the data members of the class. For example
class Cellphone //1: mem-init
{
private:
long number;
bool on;
public:
Cellphone (long n, bool ison) : number(n), on(ison) {}
};
The constructor of Cellphone can also be written as follows:
Cellphone (long n, bool ison) //2 initialization within constructor's
body
{
number = n;
on = ison;
}
There is no substantial difference between the two forms in the case of Cellphone's
constructor. This is due to the way mem-initialization lists are processed by the compiler.
The compiler scans the mem-initialization list and inserts the initialization code into the
constructor's body before any user-written code. Thus, the constructor in the first
example is expanded by the compiler into the constructor in the second example.
Nonetheless, the choice between using a mem-initialization list and initialization inside
the constructor's body is significant in the following four cases:
" Initialization of const members
" Initialization of reference members
" Passing arguments to a constructor of a base class or an embedded object
" Initialization of member objects
In the first three cases, a mem-initialization list is mandatory; in the fourth case, it is
optional. Consider the concrete examples that are discussed in the following paragraphs.'
const Data Members
const data members of a class, including const members of a base or embedded
subobject, must be initialized in a mem-initialization list.
class Allocator
{
private:
const int chunk_size;
public:
Allocator(int size) : chunk_size(size) {}
};
Reference Data Members
A reference data member must be initialized by a mem-initialization list.
class Phone;
class Modem
{
private:
Phone & line;
public:
Modem(Phone & ln) : line(ln) {}
};
Invoking A Constructor Of A Base Or A Member Object With Arguments
When a constructor has to pass arguments to the constructor of its base class or to the
constructor of an embedded object, a mem-initializer must be used.
class base
{
private:
int num1;
char * text;
public:
base(int n1, char * t) {num1 = n1; text = t; } //no default
constructor
};
class derived : public base
{
private:
char *buf;
public:
derived (int n, char * t) : base(n, t) //pass arguments to base
constructor
{ buf = (new char[100]);}
};
Embedded Objects
Consider the following example:
#include
using std::string;
class Website
{
private:
string URL
unsigned int IP
public:
Website()
{
URL = "";
IP = 0;
}
};
Class Website has an embedded object of type std::string. The syntax rules of the
language do not force the usage of mem-initialization to initialize this member. However,
the performance gain in choosing mem-initialization over initialization inside the
constructor's body is significant. Why? The initialization inside the constructor's body is
very inefficient because it requires the construction of the member URL; a temporary
std::string object is then constructed from the value "", which is in turn assigned to
URL. Finally, the temporary object has to be destroyed. The use of a mem-initialization
list, on the other hand, avoids the creation and destruction of a temporary object (the
performance implications of mem-initialization lists are discussed in further detail in
Chapter 12, "Optimizing Your Code").
""The Order Of A Mem-Initialization List Must Match The Order Of Class
Member Declarations
Due to the performance difference between the two forms of initializing embedded
objects, some programmers use mem-initialization exclusively -- even for fundamental
types. It is important to note, however, that the order of the initialization list has to match
the order of declarations within the class. This is because the compiler transforms the list
so that it coincides with the order of the declaration of the class members, regardless of
the order specified by the programmer. For example
class Website
{
private:
string URL; //1
unsigned int IP; //2
public:
Website() : IP(0), URL("") {} // initialized in reverse order
};
In the mem-initialization list, the programmer first initializes the member IP, and then
URL, even though IP is declared after URL. The compiler transforms the initialization list
to the order of the member declarations within the class. In this case, the reverse order is
harmless. When there are dependencies in the order of initialization list, however, this
transformation can cause unexpected surprises. For example
class string
{
private:
char *buff;
int capacity;
public:
explicit string(int size) :
capacity(size), buff (new char [capacity]) {} undefined behavior
};
The mem-initialization list in the constructor of string does not follow the order of [ Pobierz całość w formacie PDF ]
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • szamanka888.keep.pl