Scope Resolution Operator:: (C++ Only)
Scope Resolution Operator:: (C++ Only)
The :: (scope resolution) operator is used to qualify hidden names so that you can still
use them. You can use the unary scope operator if a namespace scope or global
scope name is hidden by an explicit declaration of the same name in a block or class.
For example:
int count = 0;
int main(void) {
int count = 0;
::count = 1; // set global count to 1
count = 2; // set local count to 2
return 0;
}
The declaration of count declared in the main function hides the integer
named count declared in global namespace scope. The statement ::count =
1 accesses the variable named count declared in global namespace scope.
You can also use the class scope operator to qualify class names or class member
names. If a class member name is hidden, you can use it by qualifying it with its class
name and the class scope operator.
In the following example, the declaration of the variable X hides the class type X, but
you can still use the static class member count by qualifying it with the class
type X and the scope resolution operator.
#include <iostream>
using namespace std;
class X
{
public:
static int count;
};
int X::count = 10; // define static data member
int main ()
{
int X = 0; // hides class type X
cout << X::count << endl; // use static member of class
X
}
Destructors
We’ve seen that a special member function—the constructor—is called automatically
when an object is first created. You might guess that another function is called
automatically when an object is destroyed. This is indeed the case. Such a function is
called a destructor. A destructor has the same name as the constructor (which is the
same as the class name) but is preceded by a tilde:
class Foo
{
private: int data;
public: Foo() : data(0) //constructor (same name as class) { }
~Foo() //destructor (same name with tilde { }
};
Like constructors, destructors do not have a return value. They also take no arguments
(the assumption being that there’s only one way to destroy an object). The most
common use of destructors is to deallocate memory that was allocated for the object
by the constructor.
#include <iostream>
using namespace std;
class Line {
public:
void setLength( double len );
double getLength( void );
Line(); // This is the constructor declaration
~Line(); // This is the destructor: declaration
private:
double length;
};
The declaration in this definition contains some unfamiliar syntax. The function name,
setLength(), is preceded by the class name, Line, and a new symbol—the double colon
(::). This symbol is called the scope resolution operator. It is a way of specifying what
class something is associated with. In this situation, void Line::setLength( double
len ) means “the setLength( double len ) member function of the Line class.”
Figure 6.5 shows its usage.
When a function is called there is some overhead ( creation of stack , pushing values,
saving return address) in other words function calls are expensive , so when you make
a function inline it is not called instead its code is replaced at the place of call.
For small program's it really doesn't make much difference if you define member in
class or outside the class using scole resolution operator.
Lets say you have h class which has about 50 member functions. If you define every
function in the body of class that will make the code very confusing for someone who
need to understand and tweak it.
So what you do... you make two files one is interface where you declare the class and
another implementation where you give definitions for all the members.
Now if someone need to understand the functionality of your class he can use the
interface file and doesn't have to go through unnecessary code.
Normally the interface file is a header file and implementation file is source file .
Overloaded Constructors
It’s convenient to be able to give variables of type Distance a value when they are first
created. That is, we would like to use definitions like
which defines an object, width, and simultaneously initializes it to a value of 5 for feet
and 6.25 for inches.
To do this we write a constructor like this:
This sets the member data feet and inches to whatever values are passed as
arguments to the constructor. So far so good. However, we also want to define
variables of type Distance without initializing them, as we did in ENGLOBJ.
The data members are initialized to constant values, in this case the integer value 0
and the float value 0.0, for feet and inches respectively. Now we can use objects
initialized with the no-argument constructor and be confident that they represent no
distance (0 feet plus 0.0 inches) rather than some arbitrary value.
Since there are now two explicit constructors with the same name, Distance(), we say
the constructor is overloaded. Which of the two constructors is executed when an
object is created depends on how many arguments are used in the definition:
// ecopycon.cpp
// initialize objects using default copy constructor
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Distance //English Distance class
{
private:
int feet;
float inches;
public:
//constructor (no args)
Distance() : feet(0), inches(0.0)
{}
//Note: no one-arg constructor
//constructor (two args)
Distance(int ft, float in) : feet(ft), inches(in)
{}
void getdist() //get length from user
{
cout << “\nEnter feet: “; cin >> feet;
cout << “Enter inches: “; cin >> inches;
}
void showdist() //display distance
{ cout << feet << “\’-” << inches << ‘\”’; }
};
////////////////////////////////////////////////////////////////
int main()
{
Distance dist1(11, 6.25); //two-arg constructor
Distance dist2(dist1); //one-arg constructor
Distance dist3 = dist1; //also one-arg constructor
//display all lengths
cout << “\ndist1 = “; dist1.showdist();
cout << “\ndist2 = “; dist2.showdist();
cout << “\ndist3 = “; dist3.showdist();
cout << endl;
return 0;
}
We initialize dist1 to the value of 11’-6.25” using the two-argument constructor. Then
we define two more objects of type Distance, dist2 and dist3, initializing both to the
value of dist1. You might think this would require us to define a one-argument
constructor, but initializing an object with another object of the same type is a special
case. These definitions both use the default copy constructor. The object dist2 is
initialized in the statement Distance dist2(dist1);
This causes the default copy constructor for the Distance class to perform a member-
by-member copy of dist1 into dist2. Surprisingly, a different format has exactly the
same effect, causing dist1 to be copied member-by-member into dist3:
Distance dist3 = dist1;
Although this looks like an assignment statement, it is not. Both formats invoke the
default copy constructor, and can be used interchangeably. Here’s the output from the
program:
dist1 = 11’-6.25”
dist2 = 11’-6.25”
dist3 = 11’-6.25”
This shows that the dist2 and dist3 objects have been initialized to the same value as
dist1.