1)
main()
{
char a[4]="HELLO";
printf("%s",a);
}
Answer:
Compiler error: Too many initializers
Explanation:
The array a is of size 4 but the string constant requires 6 bytes to get
stored.
174)
main()
{
char a[4]="HELL";
printf("%s",a);
}
Answer:
HELL%@!~@!@???@~~!
Explanation:
The character array has the memory just enough to hold the string
“HELL” and doesnt have enough space to store the terminating null
character. So it prints the HELL correctly and continues to print garbage
values till it accidentally comes across a NULL character.
Thursday, October 21, 2010
Friendship isn't inherited, transitive, or reciprocal
Just because I grant you friendship access to me doesn't automatically grant your kids access to me, doesn't automatically grant your friends access to me, and doesn't automatically grant me access to you.
- I don't necessarily trust the kids of my friends. The privileges of friendship aren't inherited. Derived classes of a friend aren't necessarily friends. If class Fred declares that class Base is a friend, classes derived from Base don't have any automatic special access rights to Fred objects.
- I don't necessarily trust the friends of my friends. The privileges of friendship aren't transitive. A friend of a friend isn't necessarily a friend. If class Fred declares class Wilma as a friend, and class Wilma declares class Betty as a friend, class Betty doesn't necessarily have any special access rights to Fred objects.
- You don't necessarily trust me simply because I declare you my friend. The privileges of friendship aren't reciprocal. If class Fred declares that class Wilma is a friend, Wilma objects have special access to Fred objects but Fred objects do not automatically have special access to Wilma objects.
Should I design my classes from the outside (interfaces first) or from the inside (data first)?
First think about what the object logically represents, not how you intend to physically build it. For example, suppose you have a Stack class that will be built by containing a LinkedList:
get() method that returns the LinkedList? Or a set() method that takes a LinkedList? Or a constructor that takes a LinkedList? Obviously the answer is No, since you should design your interfaces from the outside-in. I.e., users of Stack objects don't care about LinkedLists; they care about pushing and popping.
Now for another example that is a bit more subtle. Suppose class LinkedList is built using a linked list of Node objects, where each Node object has a pointer to the next Node:
get() method that will let users access the first Node? Should the Node object have a get() method that will let users follow that Node to the next Node in the chain? In other words, what should a LinkedList look like from the outside? Is a LinkedList really a chain of Node objects? Or is that just an implementation detail? And if it is just an implementation detail, how will the LinkedList let users access each of the elements in the LinkedList one at a time?
The key insight is the realization that a LinkedList is not a chain of Nodes. That may be how it is built, but that is not what it is. What it is is a sequence of elements. Therefore the LinkedList abstraction should provide a LinkedListIterator class as well, and that LinkedListIterator might have anoperator++ to go to the next element, and it might have a get() /set() pair to access its value stored in the Node (the value in the Node element is solely the responsibility of the LinkedList user, which is why there is a get() /set() pair that allows the user to freely manipulate that value).
Starting from the user's perspective, we might want our LinkedList class to support operations that look similar to accessing an array using pointer arithmetic:
begin() method and an end() method. These return a LinkedListIterator object. The LinkedListIterator will need a method to go forward, ++p ; a method to access the current element, *p ; and a comparison operator, p != a.end() .
The code follows. The important thing to notice is that LinkedList does not have any methods that let users access Nodes. Nodes are an implementation technique that is completely buried. This makes the LinkedList class safer (no chance a user will mess up the invariants and linkages between the various nodes), easier to use (users don't need to expend extra effort keeping the node-count equal to the actual number of nodes, or any other infrastructure stuff), and more flexible (by changing a single typedef, users could change their code from using LinkedList to some other list-like class and the bulk of their code would compile cleanly and hopefully with improved performance characteristics).
Thus the onlyget() /set() methods were to get and set the elements of the linked list, but not the infrastructure of the linked list. Since the linked list hides the infrastructure pointers/etc., it is able to make very strong promises regarding that infrastructure (e.g., if it were a doubly linked list, it might guarantee that every forward pointer was matched by a backwards pointer from the next Node).
So, we see here an example of where the values of some of a class's data is the responsibility of users (in which case the class needs to haveget() /set() methods for that data) but the data that the class wants to control does not necessarily have get() /set() methods.
Note: the purpose of this example is not to show you how to write a linked-list class. In fact you should not "roll your own" linked-list class since you should use one of the "container classes" provided with your compiler. Ideally you'll use one of the standard container classes such as thestd::list<T> template.
class Stack {
public:
...
private:
LinkedList list_;
};
Should the Stack have a public:
...
private:
LinkedList list_;
};
Now for another example that is a bit more subtle. Suppose class LinkedList is built using a linked list of Node objects, where each Node object has a pointer to the next Node:
class Node { /*...*/ };
class LinkedList {
public:
...
private:
Node* first_;
};
Should the LinkedList class have a class LinkedList {
public:
...
private:
Node* first_;
};
The key insight is the realization that a LinkedList is not a chain of Nodes. That may be how it is built, but that is not what it is. What it is is a sequence of elements. Therefore the LinkedList abstraction should provide a LinkedListIterator class as well, and that LinkedListIterator might have an
Starting from the user's perspective, we might want our LinkedList class to support operations that look similar to accessing an array using pointer arithmetic:
void userCode(LinkedList& a)
{
for (LinkedListIterator p = a.begin(); p != a.end(); ++p)
std::cout << *p << '\n';
}
To implement this interface, LinkedList will need a {
for (LinkedListIterator p = a.begin(); p != a.end(); ++p)
std::cout << *p << '\n';
}
The code follows. The important thing to notice is that LinkedList does not have any methods that let users access Nodes. Nodes are an implementation technique that is completely buried. This makes the LinkedList class safer (no chance a user will mess up the invariants and linkages between the various nodes), easier to use (users don't need to expend extra effort keeping the node-count equal to the actual number of nodes, or any other infrastructure stuff), and more flexible (by changing a single typedef, users could change their code from using LinkedList to some other list-like class and the bulk of their code would compile cleanly and hopefully with improved performance characteristics).
#include <cassert> // Poor man's exception handling
class LinkedListIterator;
class LinkedList;
class Node {
// No public members; this is a "private class"
friend class LinkedListIterator; // A friend class
friend class LinkedList;
Node* next_;
int elem_;
};
class LinkedListIterator {
public:
bool operator== (LinkedListIterator i) const;
bool operator!= (LinkedListIterator i) const;
void operator++ (); // Go to the next element
int& operator* (); // Access the current element
private:
LinkedListIterator(Node* p);
Node* p_;
friend class LinkedList; // so LinkedList can construct a LinkedListIterator
};
class LinkedList {
public:
void append(int elem); // Adds elem after the end
void prepend(int elem); // Adds elem before the beginning
...
LinkedListIterator begin();
LinkedListIterator end();
...
private:
Node* first_;
};
Here are the methods that are obviously inlinable (probably in the same header file): class LinkedListIterator;
class LinkedList;
class Node {
// No public members; this is a "private class"
friend class LinkedListIterator; // A friend class
friend class LinkedList;
Node* next_;
int elem_;
};
class LinkedListIterator {
public:
bool operator== (LinkedListIterator i) const;
bool operator!= (LinkedListIterator i) const;
void operator++ (); // Go to the next element
int& operator* (); // Access the current element
private:
LinkedListIterator(Node* p);
Node* p_;
friend class LinkedList; // so LinkedList can construct a LinkedListIterator
};
class LinkedList {
public:
void append(int elem); // Adds elem after the end
void prepend(int elem); // Adds elem before the beginning
...
LinkedListIterator begin();
LinkedListIterator end();
...
private:
Node* first_;
};
inline bool LinkedListIterator::operator== (LinkedListIterator i) const
{
return p_ == i.p_;
}
inline bool LinkedListIterator::operator!= (LinkedListIterator i) const
{
return p_ != i.p_;
}
inline void LinkedListIterator::operator++()
{
assert(p_ != NULL); // orif (p_==NULL) throw ...
p_ = p_->next_;
}
inline int& LinkedListIterator::operator*()
{
assert(p_ != NULL); // orif (p_==NULL) throw ...
return p_->elem_;
}
inline LinkedListIterator::LinkedListIterator(Node* p)
: p_(p)
{ }
inline LinkedListIterator LinkedList::begin()
{
return first_;
}
inline LinkedListIterator LinkedList::end()
{
return NULL;
}
Conclusion: The linked list had two different kinds of data. The values of the elements stored in the linked list are the responsibility of the user of the linked list (and only the user; the linked list itself makes no attempt to prohibit users from changing the third element to 5), and the linked list's infrastructure data (next pointers, etc.), whose values are the responsibility of the linked list (and only the linked list; e.g., the linked list does not let users change (or even look at!) the various next pointers). {
return p_ == i.p_;
}
inline bool LinkedListIterator::operator!= (LinkedListIterator i) const
{
return p_ != i.p_;
}
inline void LinkedListIterator::operator++()
{
assert(p_ != NULL); // or
p_ = p_->next_;
}
inline int& LinkedListIterator::operator*()
{
assert(p_ != NULL); // or
return p_->elem_;
}
inline LinkedListIterator::LinkedListIterator(Node* p)
: p_(p)
{ }
inline LinkedListIterator LinkedList::begin()
{
return first_;
}
inline LinkedListIterator LinkedList::end()
{
return NULL;
}
Thus the only
So, we see here an example of where the values of some of a class's data is the responsibility of users (in which case the class needs to have
Note: the purpose of this example is not to show you how to write a linked-list class. In fact you should not "roll your own" linked-list class since you should use one of the "container classes" provided with your compiler. Ideally you'll use one of the standard container classes such as the
() vs [] for subscripting in case of more than 1 parameter
Use operator() rather than operator[] .
When you have multiple subscripts, the cleanest way to do it is withoperator() rather than with operator[] . The reason is that operator[] always takes exactly one parameter, but operator() can take any number of parameters (in the case of a rectangular matrix, two parameters are needed).
For example:
m(i,j) rather than m[i][j] :
When you have multiple subscripts, the cleanest way to do it is with
For example:
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double& operator() (unsigned row, unsigned col); ← subscript operators often come in pairs
double operator() (unsigned row, unsigned col) const; ← subscript operators often come in pairs
...
~Matrix(); // Destructor
Matrix(Matrix const& m); // Copy constructor
Matrix& operator= (Matrix const& m); // Assignment operator
...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//data_ <--initialized below (after the 'if/throw' statement)
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= rows_ || col >= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= rows_ || col >= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
Then you can access an element of Matrix m using public:
Matrix(unsigned rows, unsigned cols);
double& operator() (unsigned row, unsigned col); ← subscript operators often come in pairs
double operator() (unsigned row, unsigned col) const; ← subscript operators often come in pairs
...
~Matrix(); // Destructor
Matrix(Matrix const& m); // Copy constructor
Matrix& operator= (Matrix const& m); // Assignment operator
...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//data_ <--initialized below (after the 'if/throw' statement)
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= rows_ || col >= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= rows_ || col >= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
int main()
{
Matrix m(10,10);
m(5,8) = 106.15;
std::cout << m(5,8);
...
}
{
Matrix m(10,10);
m(5,8) = 106.15;
std::cout << m(5,8);
...
}
Matrix class is not array of arrays
The same reasons you encapsulate your data structures, and the same reason you check parameters to make sure they are valid.
A few people use[][] despite its limitations, arguing that [][] is better because it is faster or because it uses C-syntax. The problem with the "it's faster" argument is that it's not — at least not on the latest version of two of the world's best known C++ compilers. The problem with the "uses C-syntax" argument is that C++ is not C. Plus, oh yea, the C-syntax makes it harder to change the data structure and harder to check parameter values.
The point of the previous two FAQs is thatm(i,j) gives you a clean, simple way to check all the parameters and to hide (and therefore, if you want to, change) the internal data structure. The world already has way too many exposed data structures and way too many out-of-bounds parameters, and those cost way too much money and cause way too many delays and way too many defects.
Now everybody knows that you are different. You are clairvoiant with perfect knowledge of the future, and you know that no one will ever find any benefit from changing your matrix's internal data structure. Plus you are a good programmer, unlike those slobs out there that occasionally pass wrong parameters, so you don't need to worry about pesky little things like parameter checking. But even though you don't need to worry about maintenance costs (no one ever needs to change your code), there might be one or two other programmers who aren't quite perfect yet. For them, maintenance costs are high, defects are real, and requirements change. Believe it or not, every once in a while they need to (better sit down) change their code.
Okay, my thongue wath in my theek. But there was a point. The point was that encapsulation and parameter-checking are not crutches for the weak. It's smart to use techniques that make encapsulation and/or parameter checking easy. Them(i,j) syntax is one of those techniques.
Having said all that, if you find yourself maintaining a billion-line app where the original team usedm[i][j] , or even if you are writing a brand new app and you just plain want to use m[i][j] , you can still encapsulate the data structure and/or check all your parameters. It's not even that hard. However it does require a level of sophistication that, like it or not, the average C++ programmers fears. Fortunately you are not average, so read on.
If you merely want to check parameters, just make sure the outeroperator[] returns an object rather than a raw array, then that object's operator[] can check its parameter in the usual way. Beware that this can slow down your program. In particular, if these inner array-like objects end up allocating their own block of memory for their row of the matrix, the performance overhead for creating / destroying your matrix objects can grow dramatically. The theoretical cost is still O(rows*cols), but in practice, the overhead of the memory allocator (new or malloc) can be much larger than anything else, and that overhead can swamp the other costs. For instance, on two of the world's best known C++ compilers, the separate-allocation-per-row technique was 10x slower than the than one-allocation-for-the-entire-matrix technique. 10% is one thing, 10x is another.
If you want to check the parameters without the above overhead and/or if you want to encapsulate (and possibly change) the matrix's internal data structure, follow these steps:
Matrix::ConstRow . Don't forget to use Matrix const& instead of Matrix& .
Final step: find the joker who failed to read the previous FAQ and thonk him in the noggin.
If you have a decent compiler and if you judiciously use inlining, the compiler should optimize away the temporary objects. In other words, theoperator[] -approach above will hopefully not be slower than what it would have been if you had directly called Matrix::operator()(unsigned row, unsigned col) in the first place. Of course you could have made your life simpler and avoided most of the above work by directly calling Matrix::operator()(unsigned row, unsigned col) in the first place. So you might as well directly call Matrix::operator()(unsigned row, unsigned col) in the first place.
A few people use
The point of the previous two FAQs is that
Now everybody knows that you are different. You are clairvoiant with perfect knowledge of the future, and you know that no one will ever find any benefit from changing your matrix's internal data structure. Plus you are a good programmer, unlike those slobs out there that occasionally pass wrong parameters, so you don't need to worry about pesky little things like parameter checking. But even though you don't need to worry about maintenance costs (no one ever needs to change your code), there might be one or two other programmers who aren't quite perfect yet. For them, maintenance costs are high, defects are real, and requirements change. Believe it or not, every once in a while they need to (better sit down) change their code.
Okay, my thongue wath in my theek. But there was a point. The point was that encapsulation and parameter-checking are not crutches for the weak. It's smart to use techniques that make encapsulation and/or parameter checking easy. The
Having said all that, if you find yourself maintaining a billion-line app where the original team used
If you merely want to check parameters, just make sure the outer
If you want to check the parameters without the above overhead and/or if you want to encapsulate (and possibly change) the matrix's internal data structure, follow these steps:
- Add
operator()(unsigned row, unsigned col) to the Matrix class. - Create nested class
Matrix::Row . It should have a ctor with parameters(Matrix& matrix, unsigned row) , and it should store those two values in its this object. - Change
Matrix::operator[](unsigned row) so it returns an object of classMatrix::Row , e.g.,{ return Row(*this,row); } . - Class
Matrix::Row then defines its ownoperator[](unsigned col) which turns around and calls, you guessed it,Matrix::operator()(unsigned row, unsigned col) . If theMatrix::Row data members are calledMatrix& matrix_ andunsigned row_ , the code forMatrix::Row::operator[](unsigned col) will be{ return matrix_(row_, col); }
Final step: find the joker who failed to read the previous FAQ and thonk him in the noggin.
If you have a decent compiler and if you judiciously use inlining, the compiler should optimize away the temporary objects. In other words, the
Overloading < And >
Without friend
int operator > (const Complex& right) const { return (real > right.getReal() && img > right.getImg(); }
Using Friend
friend int operator < (const Complex& left, const Complex& right){----//TODO}
int operator > (const Complex& right) const { return (real > right.getReal() && img > right.getImg(); }
Using Friend
friend int operator < (const Complex& left, const Complex& right){----//TODO}
Operator Overloading in c++
In C++ the overloading principle applies not only to functions, but to operators too. That is, the meaning of operators can be extended from built-in types to user-defined types. In this way a programmer can provide his or her own operator to a class by overloading the built-in operator to perform some specific computation when the operator is used with objects of that class.
One question may arise here: is this really useful in real world implementations? Some programmers consider that overloading is not useful most of the time. This and the fact that overloading makes the language more complicated is the main reason why operator overloading is banned in Java.
Even if overloading adds complexity to the language it can provide a lot of syntactic sugar, and code written by a programmer using operator overloading can be easy, but sometimes misleading, to read. We can use operator overloading easily without knowing all the implementation's complexities. A short example will make things clear:
In order to be able to write the above code we must have the "+" operator overloaded to make the proper addition between the real members and the imaginary ones and also the assignment operator. The overloading syntax is quite simple, similar to function overloading, the keyword operator followed by the operator we want to overload as you can see in the next code sample:
The motivation for doing so can be understood by examining the difference between the two choices: when the operator is a member the first object in the expression must be of that particular type, when it's a global function, the implicit or user-defined conversion can allow the operator to act even if the first operand is not exactly of the same type:
Another intuitive meaning of the "+" operator from the STL string class which is overloaded to do concatenation:
The operators which cannot be overloaded -scope resolution (::), member selection (.), and member selection through a pointer to a function(.*), preprocessor convert to string(#), preprocessor concatenate (##)...See more here.
One question may arise here: is this really useful in real world implementations? Some programmers consider that overloading is not useful most of the time. This and the fact that overloading makes the language more complicated is the main reason why operator overloading is banned in Java.
Even if overloading adds complexity to the language it can provide a lot of syntactic sugar, and code written by a programmer using operator overloading can be easy, but sometimes misleading, to read. We can use operator overloading easily without knowing all the implementation's complexities. A short example will make things clear:
Complex a(1.2,1.3); //this class is used to represent complex numbersThe addition without having overloaded operator + could look like this:
Complex b(2.1,3); //notice the construction taking 2 parameters for the real and imaginary part
Complex c = a+b; //for this to work the addition operator must be overloaded
a.Add(b);This piece of code is not as suggestive as the first one and the readability becomes poor. Using operator overloading is a design decision, so when we deal with concepts where some operator seems fit and its use intuitive, it will make the code more clear than using a function to do the task. However, there are many cases when programmers abuse this technique, when the concept represented by the class is not related to the operator (like using + and - to add and remove elements from a data structure). In this cases operator overloading is a bad idea, creating confusion.
Complex c(a);
In order to be able to write the above code we must have the "+" operator overloaded to make the proper addition between the real members and the imaginary ones and also the assignment operator. The overloading syntax is quite simple, similar to function overloading, the keyword operator followed by the operator we want to overload as you can see in the next code sample:
class ComplexThe assignment operator can be overloaded similarly. Notice that we had to call the accessor function in order to get the real and imaginary parts from the parameter since they are private. In order to bypass this difficulty we could have made the operator + a friend.
{
public:
Complex(double re,double im)
:real(re),imag(im)
{};
Complex operator+(Complex);
Complex operator=(Complex);
private:
double real;
double imag;
}
Complex Complex::operator+(Complex num)
{
real = real + num.GetRealPart();
imag = imag + num.GetImagPart();
return *this;
}
friend Complex operator+(Complex);We could have defined the addition operator globally and called a member to do the actual work:
Complex operator+(Complex &num1,Complex &num2)
{
Complex temp(num1); //note the use of a copy constructor here
temp.Add(num2);
return temp;
}
The motivation for doing so can be understood by examining the difference between the two choices: when the operator is a member the first object in the expression must be of that particular type, when it's a global function, the implicit or user-defined conversion can allow the operator to act even if the first operand is not exactly of the same type:
Complex c = 2+b; //if the integer 2 can be converted by the Complex class, this expression is validThe number of operands can't be overridden, that is, a binary operator takes two operands, a unary only one. The same restriction acts for the precedence too, for example the multiplication takes place before addition. There are some operators that need the first operand to be left value: operator=, operator(), operator[] and operator->, so their use is restricted just as member functions(non-static), they can't be overloaded globally. The operator=, operator& and operator, (sequencing) have already defined meanings by default for all objects, but their meanings can be changed by overloading or erased by making them private.
Another intuitive meaning of the "+" operator from the STL string class which is overloaded to do concatenation:
string prefix("de");Using "+" to concatenate is also allowed in Java, but note that this is not extensible to other classes, and it's not a user defined behavior. Almost all operators can be overloaded in C++:
string word("composed");
string composed = prefix+word;
+ - * / % ^ & |
~ ! , = < > <= >=
++ -- << >> == != && ||
+= -= /= %= ^= & = |= *=
<<= >>= [ ] ( ) -> ->* new delete
The operators which cannot be overloaded -scope resolution (::), member selection (.), and member selection through a pointer to a function(.*), preprocessor convert to string(#), preprocessor concatenate (##)...See more here.
Tuesday, October 19, 2010
Stack in C++
#include <iostream>
using
namespace
std;
#define STACKSIZE 10
class
stack
{
private
:
int
arr[STACKSIZE+1];
int
tos;
public
:
stack();
void
push(
int
x);
int
pop();
bool
is_empty();
bool
is_full();
int
size();
void
display();
};
stack::stack()
{
tos = 0;
}
void
stack::push(
int
x)
{
if
(!is_full())
arr[tos++] = x;
else
cout <<
"Stack is full, Can not push "
<< x << endl;
}
int
stack::pop()
{
if
(!is_empty())
return
arr[--tos];
else
cout <<
"Stack is empty, cannot pop"
<< endl;
return
-1;
}
bool
stack::is_empty()
{
if
(tos == 0)
return
true
;
else
return
false
;
}
bool
stack::is_full()
{
if
(tos == STACKSIZE)
return
true
;
else
return
false
;
}
int
stack::size()
{
return
tos;
}
void
stack::display()
{
if
(tos == 0)
{
cout <<
"No elements to display"
<< endl;
return
;
}
for
(
int
i=0;i
cout << arr[i] <<
" "
;
cout << endl;
}
int
main()
{
stack mystack;
cout << mystack.size() << endl;
mystack.push(1);
if
(mystack.is_full())
cout <<
"stack is full"
<< endl;
mystack.pop();
if
(mystack.is_empty())
cout <<
"stack is empty"
<< endl;
}
Sunday, October 17, 2010
Some terms and their synonyms in programming languages
Scope/Visibility
Nested/Inner Class
Instance/Member
Class/Static
Local/Automatic variable
Nested/Inner Class
Instance/Member
Class/Static
Local/Automatic variable
Friday, September 17, 2010
Modifying Java Variables (w.r.t c and c++)
Modifying Simple Variable
The only mechanism for changing the value of a simple Java variable is an assignment statement. Java assignment syntax is identical to C assignment syntax. As in C, an assignment replaces the value of a variable named on the left- hand side of the equals sign by the value of the expression on the right- hand side of the equals sign.
Modifying Object Variable
Java object variables can be changed in two ways. Like simple variables, you can make assignments to object variables. When this is done the object referenced by the variable is not changed. Instead, the reference is replaced by a reference to a different object.
With a few exceptions, the only other thing that you can do with an object variable is to send it a message. This is an important part of any Java program, allowing communication between objects.
The only mechanism for changing the value of a simple Java variable is an assignment statement. Java assignment syntax is identical to C assignment syntax. As in C, an assignment replaces the value of a variable named on the left- hand side of the equals sign by the value of the expression on the right- hand side of the equals sign.
Modifying Object Variable
Java object variables can be changed in two ways. Like simple variables, you can make assignments to object variables. When this is done the object referenced by the variable is not changed. Instead, the reference is replaced by a reference to a different object.
With a few exceptions, the only other thing that you can do with an object variable is to send it a message. This is an important part of any Java program, allowing communication between objects.
Wednesday, September 15, 2010
Java and CPP - the differences and similarities
This list of similarities and differences is based heavily on The Java Language Environment, A White Paper by James Gosling and Henry McGilton http://java.sun.com/doc/language_environment/ and the soon-to-be published book, Thinking in Java by Bruce Eckel, http://www.EckelObjects.com/. At least these were the correct URLs at one point in time. Be aware, however, that the web is a dynamic environment and the URLs may change in the future.
Java does not support typedefs, defines, or a preprocessor. Without a preprocessor, there are no provisions for including header files.
Since Java does not have a preprocessor there is no concept of #define macros or manifest constants. However, the declaration of named constants is supported in Java through use of the final keyword.
Java does not support enums but, as mentioned above, does support named constants.
Java supports classes, but does not support structures or unions.
All stand-alone C++ programs require a function named main and can have numerous other functions, including both stand-alone functions and functions, which are members of a class. There are no stand-alone functions in Java. Instead, there are only functions that are members of a class, usually called methods. Global functions and global data are not allowed in Java.
All classes in Java ultimately inherit from the Object class. This is significantly different from C++ where it is possible to create inheritance trees that are completely unrelated to one another.
All function or method definitions in Java are contained within the class definition. To a C++ programmer, they may look like inline function definitions, but they aren't. Java doesn't allow the programmer to request that a function be made inline, at least not directly.
Both C++ and Java support class (static) methods or functions that can be called without the requirement to instantiate an object of the class.
The interface keyword in Java is used to create the equivalence of an abstract base class containing only method declarations and constants. No variable data members or method definitions are allowed. (True abstract base classes can also be created in Java.) The interface concept is not supported by C++.
Java does not support multiple inheritance. To some extent, the interface feature provides the desirable features of multiple inheritance to a Java program without some of the underlying problems.
While Java does not support multiple inheritance, single inheritance in Java is similar to C++, but the manner in which you implement inheritance differs significantly, especially with respect to the use of constructors in the inheritance chain.
In addition to the access specifiers applied to individual members of a class, C++ allows you to provide an additional access specifier when inheriting from a class. This latter concept is not supported by Java.
Java does not support the goto statement (but goto is a reserved word). However, it does support labeled break and continue statements, a feature not supported by C++. In certain restricted situations, labeled break and continue statements can be used where a goto statement might otherwise be used.
Java does not support operator overloading.
Java does not support automatic type conversions (except where guaranteed safe).
Unlike C++, Java has a String type, and objects of this type are immutable (cannot be modified). Quoted strings are automatically converted into String objects. Java also has a StringBuffer type. Objects of this type can be modified, and a variety of string manipulation methods are provided.
Unlike C++, Java provides true arrays as first-class objects. There is a length member, which tells you how big the array is. An exception is thrown if you attempt to access an array out of bounds. All arrays are instantiated in dynamic memory and assignment of one array to another is allowed. However, when you make such an assignment, you simply have two references to the same array. Changing the value of an element in the array using one of the references changes the value insofar as both references are concerned.
Unlike C++, having two "pointers" or references to the same object in dynamic memory is not necessarily a problem (but it can result in somewhat confusing results). In Java, dynamic memory is reclaimed automatically, but is not reclaimed until all references to that memory become NULL or cease to exist. Therefore, unlike in C++, the allocated dynamic memory cannot become invalid for as long as it is being referenced by any reference variable.
Java does not support pointers (at least it does not allow you to modify the address contained in a pointer or to perform pointer arithmetic). Much of the need for pointers was eliminated by providing types for arrays and strings. For example, the oft-used C++ declaration char* ptr needed to point to the first character in a C++ null-terminated "string" is not required in Java, because a string is a true object in Java.
A class definition in Java looks similar to a class definition in C++, but there is no closing semicolon. Also forward reference declarations that are sometimes required in C++ are not required in Java.
The scope resolution operator (::) required in C++ is not used in Java. The dot is used to construct all fully-qualified references. Also, since there are no pointers, the pointer operator (->) used in C++ is not required in Java.
In C++, static data members and functions are called using the name of the class and the name of the static member connected by the scope resolution operator. In Java, the dot is used for this purpose.
Like C++, Java has primitive types such as int, float, etc. Unlike C++, the size of each primitive type is the same regardless of the platform. There is no unsigned integer type in Java. Type checking and type requirements are much tighter in Java than in C++.
Unlike C++, Java provides a true boolean type.
Conditional expressions in Java must evaluate to boolean rather than to integer, as is the case in C++. Statements such as if(x+y)... are not allowed in Java because the conditional expression doesn't evaluate to a boolean.
The char type in C++ is an 8-bit type that maps to the ASCII (or extended ASCII) character set. The char type in Java is a 16-bit type and uses the Unicode character set (the Unicode values from 0 through 127 match the ASCII character set). For information on the Unicode character set see http://www.stonehand.com/unicode.html.
Unlike C++, the >> operator in Java is a "signed" right bit shift, inserting the sign bit into the vacated bit position. Java adds an operator that inserts zeros into the vacated bit positions.
C++ allows the instantiation of variables or objects of all types either at compile time in static memory or at run time using dynamic memory. However, Java requires all variables of primitive types to be instantiated at compile time, and requires all objects to be instantiated in dynamic memory at runtime. Wrapper classes are provided for all primitive types except byte and short to allow them to be instantiated as objects in dynamic memory at runtime if needed.
C++ requires that classes and functions be declared before they are used. This is not necessary in Java.
The "namespace" issues prevalent in C++ are handled in Java by including everything in a class, and collecting classes into packages.
C++ requires that you re-declare static data members outside the class. This is not required in Java.
In C++, unless you specifically initialize variables of primitive types, they will contain garbage. Although local variables of primitive types can be initialized in the declaration, primitive data members of a class cannot be initialized in the class definition in C++.
In Java, you can initialize primitive data members in the class definition. You can also initialize them in the constructor. If you fail to initialize them, they will be initialized to zero (or equivalent) automatically.
Like C++, Java supports constructors that may be overloaded. As in C++, if you fail to provide a constructor, a default constructor will be provided for you. If you provide a constructor, the default constructor is not provided automatically.
All objects in Java are passed by reference, eliminating the need for the copy constructor used in C++.
Like C++, Java allows you to overload functions. However, default arguments are not supported by Java.
Unlike C++, Java does not support templates. Thus, there are no generic functions or classes.
Unlike C++, several "data structure" classes are contained in the "standard" version of Java. More specifically, they are contained in the standard class library that is distributed with the Java Development Kit (JDK). For example, the standard version of Java provides the containers Vector and Hashtable that can be used to contain any object through recognition that any object is an object of type Object. However, to use these containers, you must perform the appropriate upcasting and downcasting, which may lead to efficiency problems.
Multithreading is a standard feature of the Java language.
Although Java uses the same keywords as C++ for access control: private, public, and protected, the interpretation of these keywords is significantly different between Java and C++.
There is no virtual keyword in Java. All non-static methods always use dynamic binding, so the virtual keyword isn't needed for the same purpose that it is used in C++.
Java provides the final keyword that can be used to specify that a method cannot be overridden and that it can be statically bound. (The compiler may elect to make it inline in this case.)
The detailed implementation of the exception handling system in Java is significantly different from that in C++.
Unlike C++, Java does not support operator overloading. However, the (+) and (+=) operators are automatically overloaded to concatenate strings, and to convert other types to string in the process.
As in C++, Java applications can call functions written in another language. This is commonly referred to as native methods. However, applets cannot call native methods.
Unlike C++, Java has built-in support for program documentation. Specially written comments can be automatically stripped out using a separate program named javadoc to produce program documentation.
Generally Java is more robust than C++ due to the following:
Java does not support typedefs, defines, or a preprocessor. Without a preprocessor, there are no provisions for including header files.
Since Java does not have a preprocessor there is no concept of #define macros or manifest constants. However, the declaration of named constants is supported in Java through use of the final keyword.
Java does not support enums but, as mentioned above, does support named constants.
Java supports classes, but does not support structures or unions.
All stand-alone C++ programs require a function named main and can have numerous other functions, including both stand-alone functions and functions, which are members of a class. There are no stand-alone functions in Java. Instead, there are only functions that are members of a class, usually called methods. Global functions and global data are not allowed in Java.
All classes in Java ultimately inherit from the Object class. This is significantly different from C++ where it is possible to create inheritance trees that are completely unrelated to one another.
All function or method definitions in Java are contained within the class definition. To a C++ programmer, they may look like inline function definitions, but they aren't. Java doesn't allow the programmer to request that a function be made inline, at least not directly.
Both C++ and Java support class (static) methods or functions that can be called without the requirement to instantiate an object of the class.
The interface keyword in Java is used to create the equivalence of an abstract base class containing only method declarations and constants. No variable data members or method definitions are allowed. (True abstract base classes can also be created in Java.) The interface concept is not supported by C++.
Java does not support multiple inheritance. To some extent, the interface feature provides the desirable features of multiple inheritance to a Java program without some of the underlying problems.
While Java does not support multiple inheritance, single inheritance in Java is similar to C++, but the manner in which you implement inheritance differs significantly, especially with respect to the use of constructors in the inheritance chain.
In addition to the access specifiers applied to individual members of a class, C++ allows you to provide an additional access specifier when inheriting from a class. This latter concept is not supported by Java.
Java does not support the goto statement (but goto is a reserved word). However, it does support labeled break and continue statements, a feature not supported by C++. In certain restricted situations, labeled break and continue statements can be used where a goto statement might otherwise be used.
Java does not support operator overloading.
Java does not support automatic type conversions (except where guaranteed safe).
Unlike C++, Java has a String type, and objects of this type are immutable (cannot be modified). Quoted strings are automatically converted into String objects. Java also has a StringBuffer type. Objects of this type can be modified, and a variety of string manipulation methods are provided.
Unlike C++, Java provides true arrays as first-class objects. There is a length member, which tells you how big the array is. An exception is thrown if you attempt to access an array out of bounds. All arrays are instantiated in dynamic memory and assignment of one array to another is allowed. However, when you make such an assignment, you simply have two references to the same array. Changing the value of an element in the array using one of the references changes the value insofar as both references are concerned.
Unlike C++, having two "pointers" or references to the same object in dynamic memory is not necessarily a problem (but it can result in somewhat confusing results). In Java, dynamic memory is reclaimed automatically, but is not reclaimed until all references to that memory become NULL or cease to exist. Therefore, unlike in C++, the allocated dynamic memory cannot become invalid for as long as it is being referenced by any reference variable.
Java does not support pointers (at least it does not allow you to modify the address contained in a pointer or to perform pointer arithmetic). Much of the need for pointers was eliminated by providing types for arrays and strings. For example, the oft-used C++ declaration char* ptr needed to point to the first character in a C++ null-terminated "string" is not required in Java, because a string is a true object in Java.
A class definition in Java looks similar to a class definition in C++, but there is no closing semicolon. Also forward reference declarations that are sometimes required in C++ are not required in Java.
The scope resolution operator (::) required in C++ is not used in Java. The dot is used to construct all fully-qualified references. Also, since there are no pointers, the pointer operator (->) used in C++ is not required in Java.
In C++, static data members and functions are called using the name of the class and the name of the static member connected by the scope resolution operator. In Java, the dot is used for this purpose.
Like C++, Java has primitive types such as int, float, etc. Unlike C++, the size of each primitive type is the same regardless of the platform. There is no unsigned integer type in Java. Type checking and type requirements are much tighter in Java than in C++.
Unlike C++, Java provides a true boolean type.
Conditional expressions in Java must evaluate to boolean rather than to integer, as is the case in C++. Statements such as if(x+y)... are not allowed in Java because the conditional expression doesn't evaluate to a boolean.
The char type in C++ is an 8-bit type that maps to the ASCII (or extended ASCII) character set. The char type in Java is a 16-bit type and uses the Unicode character set (the Unicode values from 0 through 127 match the ASCII character set). For information on the Unicode character set see http://www.stonehand.com/unicode.html.
Unlike C++, the >> operator in Java is a "signed" right bit shift, inserting the sign bit into the vacated bit position. Java adds an operator that inserts zeros into the vacated bit positions.
C++ allows the instantiation of variables or objects of all types either at compile time in static memory or at run time using dynamic memory. However, Java requires all variables of primitive types to be instantiated at compile time, and requires all objects to be instantiated in dynamic memory at runtime. Wrapper classes are provided for all primitive types except byte and short to allow them to be instantiated as objects in dynamic memory at runtime if needed.
C++ requires that classes and functions be declared before they are used. This is not necessary in Java.
The "namespace" issues prevalent in C++ are handled in Java by including everything in a class, and collecting classes into packages.
C++ requires that you re-declare static data members outside the class. This is not required in Java.
In C++, unless you specifically initialize variables of primitive types, they will contain garbage. Although local variables of primitive types can be initialized in the declaration, primitive data members of a class cannot be initialized in the class definition in C++.
In Java, you can initialize primitive data members in the class definition. You can also initialize them in the constructor. If you fail to initialize them, they will be initialized to zero (or equivalent) automatically.
Like C++, Java supports constructors that may be overloaded. As in C++, if you fail to provide a constructor, a default constructor will be provided for you. If you provide a constructor, the default constructor is not provided automatically.
All objects in Java are passed by reference, eliminating the need for the copy constructor used in C++.
(In reality, all parameters are passed by value in Java. However, passing a copy of a reference variable makes it possible for code in the receiving method to access the object referred to by the variable, and possibly to modify the contents of that object. However, code in the receiving method cannot cause the original reference variable to refer to a different object.)There are no destructors in Java. Unused memory is returned to the operating system by way of a garbage collector, which runs in a different thread from the main program. This leads to a whole host of subtle and extremely important differences between Java and C++.
Like C++, Java allows you to overload functions. However, default arguments are not supported by Java.
Unlike C++, Java does not support templates. Thus, there are no generic functions or classes.
Unlike C++, several "data structure" classes are contained in the "standard" version of Java. More specifically, they are contained in the standard class library that is distributed with the Java Development Kit (JDK). For example, the standard version of Java provides the containers Vector and Hashtable that can be used to contain any object through recognition that any object is an object of type Object. However, to use these containers, you must perform the appropriate upcasting and downcasting, which may lead to efficiency problems.
Multithreading is a standard feature of the Java language.
Although Java uses the same keywords as C++ for access control: private, public, and protected, the interpretation of these keywords is significantly different between Java and C++.
There is no virtual keyword in Java. All non-static methods always use dynamic binding, so the virtual keyword isn't needed for the same purpose that it is used in C++.
Java provides the final keyword that can be used to specify that a method cannot be overridden and that it can be statically bound. (The compiler may elect to make it inline in this case.)
The detailed implementation of the exception handling system in Java is significantly different from that in C++.
Unlike C++, Java does not support operator overloading. However, the (+) and (+=) operators are automatically overloaded to concatenate strings, and to convert other types to string in the process.
As in C++, Java applications can call functions written in another language. This is commonly referred to as native methods. However, applets cannot call native methods.
Unlike C++, Java has built-in support for program documentation. Specially written comments can be automatically stripped out using a separate program named javadoc to produce program documentation.
Generally Java is more robust than C++ due to the following:
- Object handles (references) are automatically initialized to null.
- Handles are checked before accessing, and exceptions are thrown in the event of problems.
- You cannot access an array out of bounds.
- Memory leaks are prevented by automatic garbage collection.
C++ ACCESSORS AND MUTATORS TUTORIAL
• I. INTRODUCTION
Hello; nice to meet you! Welcome to the “C++ Accessors and Mutators Tutorial.”
The tutorial assumes you are familiar with the following vocabulary:
1. Instantiation is declaring an object of a class type.
2. Encapsulation is the idea of an object containing data and functions that operate on that data.
3. A class is a user defined type.
4. Inheritance allows the creation of hierarchical classifications.
5. Polymorphism is Greek for “many shapes;” which becomes manipulating “many types” through a common interface. Polymorphism gives a programmer “programming in the general” instead of “programming in the specific.”
6. Object-oriented programming (OOP) is the use of inheritance, run-time polymorphism, encapsulation, and the programming style of defining your own data types as classes.
• II. PRIVATE DATA MEMBERS
The variables declared as part of the class are data members. Data hiding occurs when access control is established by data members being declared in the private area of the body of a class definition. The private access specifier prevents direct access to the class data members. However, private data members can be accessed indirectly by public accessor and mutator member functions and friends of that class.
• III. CONSTRUCTORS
When data members are declared they can not be initialized in the class body. Therefore, constructors are used to initialize the class data members when the class objects are instantiated.
• IV. GOOD ACCESSOR CHARACTERISTICS
Accessors or get functions:
1. Read or obtain the value of private member variables.
This must be done in a manner that maintains the integrity of the private member data.
2. Display the value of private member variables.
The displayed information should be user friendly, i.e., formatted in a fashion easily readable and understandably by the user.
3. Print the value of private member variables.
When an inappropriate attempt is made to change the value of a private data member, a properly written get function with good characteristics will be programmed to notify the user. User management should receive written notification of all inappropriate activity as soon as it occurs.
• V. GOOD MUTATOR CHARACTERISTICS
Mutators or set functions:
1. Modify the value of private data members.
Public set functions set the value of private data members. However, set functions should not just change data. Set functions must be programmed to make sure what they are being called to do is correct before they do it. Properly written set functions are the first line of defense against, “garbage in, garbage out.”
2. Validate the value of private data members.
When an inappropriate attempt is made to change the value of a private data member, a properly written set function will be programmed to prevent the modification.
• VI. ADVANTAGES OF USING GET AND SET FUNCTIONS
The main advantages of always using get and set public class member functions is faster, more efficient, and less expensive program maintenance.
1. All data usage updates only have to be made to the appropriate public get member functions.
2. All data value storage updates only have to be made to the appropriate public set member functions.
• VII. SUMMARY
The names of the accessor and mutator member functions do not have to begin with get and set; however, the naming convention is a generally accepted programming practice.
In general, get and set functions are a public interface for read/write access to private data members.
Even though all class member functions can indirectly access private data members, the programmer should ensure the program is written so that all member functions call the appropriate get and set functions when interacting with private data members.
Hello; nice to meet you! Welcome to the “C++ Accessors and Mutators Tutorial.”
The tutorial assumes you are familiar with the following vocabulary:
1. Instantiation is declaring an object of a class type.
2. Encapsulation is the idea of an object containing data and functions that operate on that data.
3. A class is a user defined type.
4. Inheritance allows the creation of hierarchical classifications.
5. Polymorphism is Greek for “many shapes;” which becomes manipulating “many types” through a common interface. Polymorphism gives a programmer “programming in the general” instead of “programming in the specific.”
6. Object-oriented programming (OOP) is the use of inheritance, run-time polymorphism, encapsulation, and the programming style of defining your own data types as classes.
• II. PRIVATE DATA MEMBERS
The variables declared as part of the class are data members. Data hiding occurs when access control is established by data members being declared in the private area of the body of a class definition. The private access specifier prevents direct access to the class data members. However, private data members can be accessed indirectly by public accessor and mutator member functions and friends of that class.
• III. CONSTRUCTORS
When data members are declared they can not be initialized in the class body. Therefore, constructors are used to initialize the class data members when the class objects are instantiated.
• IV. GOOD ACCESSOR CHARACTERISTICS
Accessors or get functions:
1. Read or obtain the value of private member variables.
This must be done in a manner that maintains the integrity of the private member data.
2. Display the value of private member variables.
The displayed information should be user friendly, i.e., formatted in a fashion easily readable and understandably by the user.
3. Print the value of private member variables.
When an inappropriate attempt is made to change the value of a private data member, a properly written get function with good characteristics will be programmed to notify the user. User management should receive written notification of all inappropriate activity as soon as it occurs.
• V. GOOD MUTATOR CHARACTERISTICS
Mutators or set functions:
1. Modify the value of private data members.
Public set functions set the value of private data members. However, set functions should not just change data. Set functions must be programmed to make sure what they are being called to do is correct before they do it. Properly written set functions are the first line of defense against, “garbage in, garbage out.”
2. Validate the value of private data members.
When an inappropriate attempt is made to change the value of a private data member, a properly written set function will be programmed to prevent the modification.
• VI. ADVANTAGES OF USING GET AND SET FUNCTIONS
The main advantages of always using get and set public class member functions is faster, more efficient, and less expensive program maintenance.
1. All data usage updates only have to be made to the appropriate public get member functions.
2. All data value storage updates only have to be made to the appropriate public set member functions.
• VII. SUMMARY
The names of the accessor and mutator member functions do not have to begin with get and set; however, the naming convention is a generally accepted programming practice.
In general, get and set functions are a public interface for read/write access to private data members.
Even though all class member functions can indirectly access private data members, the programmer should ensure the program is written so that all member functions call the appropriate get and set functions when interacting with private data members.
Monday, September 6, 2010
Basic tokens in perl
Comments
A common Perl-pitfall is to write cryptic code. In that context, Perl do provide for comments, albeit not very flexible. Perl treats any thing from a hash # to the end of line as a comment. Block comments are not possible. So, if you want to have a block of comments, you must ensure that each line starts with #.Statements
Everything other than comments are Perl statements, which must end with a semicolon, like the last line above. Unlike C, you need not put a wrapping character \ for long statements. A Perl statement always ends with a semicolon.Thursday, September 2, 2010
Overload the postfix and prefix version of ++
//prefix version of ++
ThreeD ThreeD::operator++()
{
x++; // increment x, y, and z
y++;
z++;
return *this;
}
//postfix operator ++
ThreeD ThreeD::operator++(int notused)
{
x++; // increment x, y, and z
y++;
z++;
return *this; // return original value
}
Which Operator are not overloaded
There are certain operators in the available set that cannot be overloaded. The general reason for the restriction is safety. If these operators were overloadable, it would somehow jeopardize or break safety mechanisms, make things harder, or confuse existing practice.
- The member selection operator.. Currently, the dot has a meaning for any member in a class, but if you allow it to be overloaded, then you couldn’t access members in the normal way; instead you’d have to use a pointer and the arrow operator->.
- The pointer to member dereference operator.*, for the same reason as operator..
- There’s no exponentiation operator. The most popular choice for this was operator** from Fortran, but this raised difficult parsing questions. Also, C has no exponentiation operator, so C++ didn’t seem to need one either because you can always perform a function call. An exponentiation operator would add a convenient notation, but no new language functionality to account for the added complexity of the compiler.
- There are no user-defined operators. That is, you can’t make up new operators that aren’t currently in the set. Part of the problem is how to determine precedence, and part of the problem is an insufficient need to account for the necessary trouble.
- You can’t change the precedence rules. They’re hard enough to remember as it is without letting people play with them.
Member access in C++
Member access determines if a class member is accessible in an expression or declaration. Suppose x is a member of class A. Class member x can be declared to have one of the following levels of accessibility:
public: x can be used anywhere without the access restrictions defined by private or protected.
private: x can be used only by the members and friends of class A.
protected: x can be used only by the members and friends of class A, and the members and friends of classes derived from class A.
Members of classes declared with the keyword class are private by default. Members of classes declared with the keyword struct or union are public by default.
To control the access of a class member, you use one of the access specifiers public, private, or protected as a label in a class member list. The following example demonstrates these access specifiers:
An access specifier specifies the accessibility of members that follow it until the next access specifier or until the end of the class definition. You can use any number of access specifiers in any order. If you later define a class member within its class definition, its access specification must be the same as its declaration. The following example demonstrates this:
Access control applies to names. In particular, if you add access control to a typedef name, it affects only the typedef name. The following example demonstrates this:
public: x can be used anywhere without the access restrictions defined by private or protected.
private: x can be used only by the members and friends of class A.
protected: x can be used only by the members and friends of class A, and the members and friends of classes derived from class A.
Members of classes declared with the keyword class are private by default. Members of classes declared with the keyword struct or union are public by default.
To control the access of a class member, you use one of the access specifiers public, private, or protected as a label in a class member list. The following example demonstrates these access specifiers:
struct A {The following table lists the access of data members A::a A::b, and A::c in various scopes of the above example.
friend class C;
private:
int a;
public:
int b;
protected:
int c;
};
struct B : A {
void f() {
// a = 1;
b = 2;
c = 3;
}
};
struct C {
void f(A x) {
x.a = 4;
x.b = 5;
x.c = 6;
}
};
int main() {
A y;
// y.a = 7;
y.b = 8;
// y.c = 9;
B z;
// z.a = 10;
z.b = 11;
// z.c = 12;
}
Scope | A::a | A::b | A::c |
---|---|---|---|
function B::f() | No access. Member A::a is private. | Access. Member A::b is public. | Access. Class B inherits from A. |
function C::f() | Access. Class C is a friend of A. | Access. Member A::b is public. | Access. Class C is a friend of A. |
object y in main() | No access. Member y.a is private. | Access. Member y.a is public. | No access. Member y.c is protected. |
object z in main() | No access. Member z.a is private. | Access. Member z.a is public. | No access. Member z.c is protected. |
class A {
class B;
public:
class B { };
};
The compiler will not allow the definition of class B because this class has already been declared as private.
A class member has the same access control regardless whether it has been defined within its class or outside its class.Access control applies to names. In particular, if you add access control to a typedef name, it affects only the typedef name. The following example demonstrates this:
class A {
class B { };
public:
typedef B C;
};
int main() {
A::C x;
// A::B y;
}
The compiler will allow the declaration A::C x because the typedef name A::C is public. The compiler would not allow the declaration A::B y because A::B is private.
Wednesday, September 1, 2010
Static function members in C+
Static member functions (C++ only)
You cannot have static and nonstatic member functions with the same names and the same number and type of arguments.
Like static data members, you may access a static member function f() of a class A without using an object of class A.
A static member function does not have a this pointer.
Eg.
class X
{
private:
static int si;
public:
static void set_si(int arg) { si = arg; }
};
Static member functions (C++ only)
A static member function can access only the names of static members, enumerators, and nested types of the class in which it is declared. Suppose a static member function f() is a member of class X. The static member function f() cannot access the nonstatic members X or the nonstatic members of a base class of X.
You cannot have static and nonstatic member functions with the same names and the same number and type of arguments.
Like static data members, you may access a static member function f() of a class A without using an object of class A.
A static member function does not have a this pointer.
Eg.
class X
{
private:
static int si;
public:
static void set_si(int arg) { si = arg; }
};
Static member functions (C++ only)
The compiler does not allow the member access operation this->si in function A::print_si() because this member function has been declared as static, and therefore does not have a this pointer.
You can call a static member function using the this pointer of a nonstatic member function. In the following example, the nonstatic member function printall() calls the static member function f() using the this pointer:#include < iostream >
using namespace std;
class C {
static void f() {
cout << "Here is i: " << i << endl;
}
static int i;
int j;
public:
C(int firstj): j(firstj) { }
void printall();
};
void C::printall() {
cout << "Here is j: " << this->j << endl;
this->f();
}
int C::i = 3;
int main() {
C obj_C(0);
obj_C.printall();
}
A static member function cannot be declared with the keywords virtual, const, volatile, or const volatile.
A static member function can access only the names of static members, enumerators, and nested types of the class in which it is declared. Suppose a static member function f() is a member of class X. The static member function f() cannot access the nonstatic members X or the nonstatic members of a base class of X.
Static data member in c++ classes
Note: Static data member are already initialised to 0, but still you should initialise explicitly using method 2.
Here are the two ways I was talking about :
First One:
Second One:
Static data members of a class in namespace scope have external linkage. The initializer for a static data member is in the scope of the class declaring the member.
A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.
You can only have one definition of a static member in a program. Unnamed classes, classes contained within unnamed classes, and local classes cannot have static data members.
Static data members and their initializers can access other static private and protected members of their class.
Here are the two ways I was talking about :
First One:
class class1{
private:
public:
class1(){}
static int DataMember;
static void initFun()
{ DataMember = 10 ; }
};
Second One:
class class2{Once you define a static data member, it exists even though no objects of the static data member's class exist. In the above example, no objects of class X exist even though the static data member X::i has been defined.
private:
public:
class2(){}
static int DataMember2;
};
int class2::DataMember2 = 10 ;
Static data members of a class in namespace scope have external linkage. The initializer for a static data member is in the scope of the class declaring the member.
A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.
You can only have one definition of a static member in a program. Unnamed classes, classes contained within unnamed classes, and local classes cannot have static data members.
Static data members and their initializers can access other static private and protected members of their class.
Using friend to overload operators
class loc {
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt) {
longitude = lg;
latitude = lt;
}
void show() {
cout << longitude << " ";
cout << latitude << "\n";
}
loc operator=(loc op2);
friend loc operator++(loc &op);
friend loc operator--(loc &op);
};
loc operator++(loc &op)
{
op.longitude++;
op.latitude++;
return op;
}
// Make op-- a friend; use reference.
loc operator--(loc &op)
{
op.longitude--;
op.latitude--;
return op;
}
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt) {
longitude = lg;
latitude = lt;
}
void show() {
cout << longitude << " ";
cout << latitude << "\n";
}
loc operator=(loc op2);
friend loc operator++(loc &op);
friend loc operator--(loc &op);
};
loc operator++(loc &op)
{
op.longitude++;
op.latitude++;
return op;
}
// Make op-- a friend; use reference.
loc operator--(loc &op)
{
op.longitude--;
op.latitude--;
return op;
}
Types of constructors
1. Void constructors or default constructors
This has no parameters and is must in case of dynamic allocation of objects.
2. Default parameter constructor
A default parameter is a function parameter that has a default value provided to it. If the user does not supply a value for this parameter, the default value will be used. If the user does supply a value for the default parameter, the user-supplied value is used.
3 Private constructors
4. Parametric constructor
It is good practice to try not to overload the constructors. It is best to declare only one constructor and give it default parameters wherever possible:
This has no parameters and is must in case of dynamic allocation of objects.
2. Default parameter constructor
A default parameter is a function parameter that has a default value provided to it. If the user does not supply a value for this parameter, the default value will be used. If the user does supply a value for the default parameter, the user-supplied value is used.
3 Private constructors
4. Parametric constructor
It is good practice to try not to overload the constructors. It is best to declare only one constructor and give it default parameters wherever possible:
using namespace std;#include <iostream>class vector{public: double x; double y; vector (double a = 0, double b = 0) { x = a; y = b; }};int main (){ vector k; cout << "vector k: " << k.x << ", " << k.y << endl << endl; vector m (45, 2); cout << "vector m: " << m.x << ", " << m.y << endl << endl; vector p (3); cout << "vector p: " << p.x << ", " << p.y << endl << endl; return 0;}output:vector k: 0, 0vector m: 45, 2vector p: 3, 0
The stack and the heap
The memory a program uses is typically divided into four different areas:
The heap
The heap (also known as the “free store”) is a large pool of memory used for dynamic allocation. In C++, when you use the new operator to allocate memory, this memory is assigned from the heap.
Because the precise location of the memory allocated is not known in advance, the memory allocated has to be accessed indirectly — which is why new returns a pointer. You do not have to worry about the mechanics behind the process of how free memory is located and allocated to the user. However, it is worth knowing that sequential memory requests may not result in sequential memory addresses being allocated!
When a dynamically allocated variable is deleted, the memory is “returned” to the heap and can then be reassigned as future allocation requests are received.
The heap has advantages and disadvantages:
1) Allocated memory stays allocated until it is specifically deallocated (beware memory leaks).
2) Dynamically allocated memory must be accessed through a pointer.
3) Because the heap is a big pool of memory, large arrays, structures, or classes should be allocated here.
The stack
The call stack (usually referred to as “the stack”) has a much more interesting role to play. Before we talk about the call stack, which refers to a particular portion of memory, let’s talk about what a stack is.
Consider a stack of plates in a cafeteria. Because each plate is heavy and they are stacked, you can really only do one of three things:
1) Look at the surface of the top plate
2) Take the top plate off the stack
3) Put a new plate on top of the stack
In computer programming, a stack is a container that holds other variables (much like an array). However, whereas an array lets you access and modify elements in any order you wish, a stack is more limited. The operations that can be performed on a stack are identical to the ones above:
1) Look at the top item on the stack (usually done via a function called top())
2) Take the top item off of the stack (done via a function called pop())
3) Put a new item on top of the stack (done via a function called push())
A stack is a last-in, first-out (LIFO) structure. The last item pushed onto the stack will be the first item popped off. If you put a new plate on top of the stack, anybody who takes a plate from the stack will take the plate you just pushed on first. Last on, first off. As items are pushed onto a stack, the stack grows larger — as items are popped off, the stack grows smaller.
The plate analogy is a pretty good analogy as to how the call stack works, but we can actually make an even better analogy. Consider a bunch of mailboxes, all stacked on top of each other. Each mailbox can only hold one item, and all mailboxes start out empty. Furthermore, each mailbox is nailed to the mailbox below it, so the number of mailboxes can not be changed. If we can’t change the number of mailboxes, how do we get a stack-like behavior?
First, we use a marker (like a post-it note) to keep track of where the bottom-most empty mailbox is. In the beginning, this will be the lowest mailbox. When we push an item onto our mailbox stack, we put it in the mailbox that is marked (which is the first empty mailbox), and move the marker up one mailbox. When we pop an item off the stack, we move the marker down one mailbox and remove the item from that mailbox. Anything below the marker is considered “on the stack”. Anything at the marker or above the marker is not on the stack.
This is almost exactly analogous to how the call stack works. The call stack is a fixed-size chunk of sequential memory addresses. The mailboxes are memory addresses, and the “items” are pieces of data (typically either variables or addreses). The “marker” is a register (a small piece of memory) in the CPU known as the stack pointer. The stack pointer keeps track of where the top of the stack currently is.
The only difference between our hypothetical mailbox stack and the call stack is that when we pop an item off the call stack, we don’t have to erase the memory (the equivalent of emptying the mailbox). We can just leave it to be overwritten by the next item pushed to that piece of memory. Because the stack pointer will be below that memory location, we know that memory location is not on the stack.
So what do we push onto our call stack? Parameters, local variables, and… function calls.
The stack in action
Because parameters and local variables essentially belong to a function, we really only need to consider what happens on the stack when we call a function. Here is the sequence of steps that takes place when a function is called:
Stack overflow
The stack has a limited size, and consequently can only hold a limited amount of information. If the program tries to put too much information on the stack, stack overflow will result. Stack overflow happens when all the memory in the stack has been allocated — in that case, further allocations begin overflowing into other sections of memory.
Stack overflow is generally the result of allocating too many variables on the stack, and/or making too many nested function calls (where function A calls function B calls function C calls function D etc…) Overflowing the stack generally causes the program to crash.
Here is an example program that causes a stack overflow. You can run it on your system and watch it crash:
This program tries to allocate a huge array on the stack. Because the stack is not large enough to handle this array, the array allocation overflows into portions of memory the program is not allowed to use. Consequently, the program crashes.
The stack has advantages and disadvantages:
- The code area, where the compiled program sits in memory.
- The globals area, where global variables are stored.
- The heap, where dynamically allocated variables are allocated from.
- The stack, where parameters and local variables are allocated from.
The heap
The heap (also known as the “free store”) is a large pool of memory used for dynamic allocation. In C++, when you use the new operator to allocate memory, this memory is assigned from the heap.
1 | int *pValue = new int ; // pValue is assigned 4 bytes from the heap |
2 | int *pArray = new int [10]; // pArray is assigned 40 bytes from the heap |
1 | int *pValue1 = new int ; |
2 | int *pValue2 = new int ; |
3 | // pValue1 and pValue2 may not have sequential addresses |
The heap has advantages and disadvantages:
1) Allocated memory stays allocated until it is specifically deallocated (beware memory leaks).
2) Dynamically allocated memory must be accessed through a pointer.
3) Because the heap is a big pool of memory, large arrays, structures, or classes should be allocated here.
The stack
The call stack (usually referred to as “the stack”) has a much more interesting role to play. Before we talk about the call stack, which refers to a particular portion of memory, let’s talk about what a stack is.
Consider a stack of plates in a cafeteria. Because each plate is heavy and they are stacked, you can really only do one of three things:
1) Look at the surface of the top plate
2) Take the top plate off the stack
3) Put a new plate on top of the stack
In computer programming, a stack is a container that holds other variables (much like an array). However, whereas an array lets you access and modify elements in any order you wish, a stack is more limited. The operations that can be performed on a stack are identical to the ones above:
1) Look at the top item on the stack (usually done via a function called top())
2) Take the top item off of the stack (done via a function called pop())
3) Put a new item on top of the stack (done via a function called push())
A stack is a last-in, first-out (LIFO) structure. The last item pushed onto the stack will be the first item popped off. If you put a new plate on top of the stack, anybody who takes a plate from the stack will take the plate you just pushed on first. Last on, first off. As items are pushed onto a stack, the stack grows larger — as items are popped off, the stack grows smaller.
The plate analogy is a pretty good analogy as to how the call stack works, but we can actually make an even better analogy. Consider a bunch of mailboxes, all stacked on top of each other. Each mailbox can only hold one item, and all mailboxes start out empty. Furthermore, each mailbox is nailed to the mailbox below it, so the number of mailboxes can not be changed. If we can’t change the number of mailboxes, how do we get a stack-like behavior?
First, we use a marker (like a post-it note) to keep track of where the bottom-most empty mailbox is. In the beginning, this will be the lowest mailbox. When we push an item onto our mailbox stack, we put it in the mailbox that is marked (which is the first empty mailbox), and move the marker up one mailbox. When we pop an item off the stack, we move the marker down one mailbox and remove the item from that mailbox. Anything below the marker is considered “on the stack”. Anything at the marker or above the marker is not on the stack.
This is almost exactly analogous to how the call stack works. The call stack is a fixed-size chunk of sequential memory addresses. The mailboxes are memory addresses, and the “items” are pieces of data (typically either variables or addreses). The “marker” is a register (a small piece of memory) in the CPU known as the stack pointer. The stack pointer keeps track of where the top of the stack currently is.
The only difference between our hypothetical mailbox stack and the call stack is that when we pop an item off the call stack, we don’t have to erase the memory (the equivalent of emptying the mailbox). We can just leave it to be overwritten by the next item pushed to that piece of memory. Because the stack pointer will be below that memory location, we know that memory location is not on the stack.
So what do we push onto our call stack? Parameters, local variables, and… function calls.
The stack in action
Because parameters and local variables essentially belong to a function, we really only need to consider what happens on the stack when we call a function. Here is the sequence of steps that takes place when a function is called:
- The address of the instruction beyond the function call is pushed onto the stack. This is how the CPU remembers where to go after the function returns.
- Room is made on the stack for the function’s return type. This is just a placeholder for now.
- The CPU jumps to the function’s code.
- The current top of the stack is held in a special pointer called the stack frame. Everything added to the stack after this point is considered “local” to the function.
- All function arguments are placed on the stack.
- The instructions inside of the function begin executing.
- Local variables are pushed onto the stack as they are defined.
- The function’s return value is copied into the placeholder that was put on the stack for this purpose.
- Everything after the stack frame pointer is popped off. This destroys all local variables and arguments.
- The return value is popped off the stack and is assigned as the value of the function. If the value of the function isn’t assigned to anything, no assignment takes place, and the value is lost.
- The address of the next instruction to execute is popped off the stack, and the CPU resumes execution at that instruction.
Stack overflow
The stack has a limited size, and consequently can only hold a limited amount of information. If the program tries to put too much information on the stack, stack overflow will result. Stack overflow happens when all the memory in the stack has been allocated — in that case, further allocations begin overflowing into other sections of memory.
Stack overflow is generally the result of allocating too many variables on the stack, and/or making too many nested function calls (where function A calls function B calls function C calls function D etc…) Overflowing the stack generally causes the program to crash.
Here is an example program that causes a stack overflow. You can run it on your system and watch it crash:
1 | int main() |
2 | { |
3 | int nStack[100000000]; |
4 | return 0; |
5 | } |
The stack has advantages and disadvantages:
- Memory allocated on the stack stays in scope as long as it is on the stack. It is destroyed when it is popped off the stack.
- All memory allocated on the stack is known at compile time. Consequently, this memory can be accessed directly through a variable.
- Because the stack is relatively small, it is generally not a good idea to do anything that eats up lots of stack space. This includes allocating large arrays, structures, and classes, as well as heavy recursion.
Subscribe to:
Posts (Atom)