Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
The
expression (a=1) assigns 1 to a and also returns 1. So, the if condition is successful and
value of a is printed as 1.
unsigned int i = 5;
while (--i >= 0)
{
cout << "Hello World\n";
} Being an unsigned number, value of i cannot be less than 0. So, the statement i >= 0
will be always true. Hence, this program goes into an infinite loop. When i becomes 0
and decremented further, it wraps around and becomes MAXINT.
--------------------------------
Smart Pointers: Reduce bugs caused by the misuse of pointers while retaining
efficiency. Like,
RAAI capability over raw ptrs.
Automatic garbage collection
Bounds checking.
a _ptr<T> is not a T *
disadv: Can’t be used with pointers created with new[].
1. Auto Ptr : Semantics of strict ownership, meaning that the auto_ptr instance is
the sole entity responsible for the object's lifetime. If an auto_ptr is copied, the
source loses the reference.
An auto_ptr containing an STL container may be used to prevent further
modification of the container
Even when implicitly copying auto_ptr objects -- for instance, if you make a
function call and pass an auto_ptr object, when the function returns, the contents
of auto_ptr will be changed to NULL
// Example 1
T* pt1 = new T;
// right now, we own the allocated object
Cyclic reference:
Ex:
struct CDad;
struct CChild;
parent->myBoy = child;
child->myDad = dad;
child.reset();
parent still references the CDad object, which itself references the CChild.If we
now call dad.reset(), we lose all "contact" with the two objects. But this leaves
both with exactly one reference, and the shared pointers see no reason to delete
either of them! We have no access to them anymore, but they mutually keep
themselves "alive". This is a memory leak at best; in the worst case, the objects
hold even more critical resources that are not released correctly.
--------------------------------------------
string s("Hello");
string t = s; // t and s point to the same buffer of characters
Stack is used for storing local variables as well as for passing parameters. Calling
function pushes the arguments into stack before control transfers to the called function. In
addition, return address and values of registers also get pushed on to the stack.
Assume that we have a class MyClass that does not have a default constructor, but which
has defined a constructor which takes an int as a parameter. This means that the compiler
is not going to provide a default constructor for the class. When such a condition is true,
the following statements hold good for MyClass
1. Every constructor for every class that has a MyClass member must explicitly initialize
the MyClass member by passing an initial int value to the MyClass constructor.
2. The compiler will not synthesize the default constructor for classes that have members
of type MyClass. If such classes want to provide a default, they must define one
explicitly, and that constructor must explicitly initialize their MyClass member.
3. The MyClass type may not be used as the element type for a dynamically allocated
array.
4. Statically allocated arrays of type MyClass must provide an explicit initializer for each
element.
5. If we have a container such as vector that holds MyClass objects, we cannot use the
constructor that takes a size without also supplying an element initializer.
Hence in our case the program does not compile because of the point 3. above
Const and Ref members can be initialized only using the construction initialization list
.e.g Sample(int nCount =
Because C defaults to external linkage for consts, this makes sense.
C++ defaults to internal linkage for const
C++ also defines a special rule for initializing const static members of an integral
type. You may initialize such members inside the class body.
Unlike ordinary data members, static members are not initialized through the class
constructor(s) and instead should be initialized when they are defined.
Functions have class scope by default.But non-static ones need some handle of sort
atleast (to be called) that is why static functions are the choice.
2): m_ciMax(255){
..................................
operator int(){
cout << "In the overloaded int() operator" << endl;
return m_nIVal;
}
cls2 = 4 * cls;
cout << cls << endl;
This program works fine. The statement cls2 = 4 * cls first converts cls to an integer
using the int() operator and then performs multiplication. It then creates a temporary
object with the result of the multiplication.
After this this temporary object is used to assign cls2 thereby invoking the overloaded=
operator. In the cout statement the int() operator is used to extract the integer from cls2
and then the resulting integer is printed using the cout object.
** Don't call virtual functions during construction or destruction, because such calls
will never go to a more derived class than that of the currently executing constructor or
destructor
Avoid techniqs :
1. //original expression was : string s= s1+s2+s3;
string temp=s1+s2;
temp+=s3;
string s=temp;
** Copy Ctor
Called in 3 cases,
1. Object being contructed(initialised) by another object.
Normally or ctor init list (incase of composition) both
2. Pass object by value
3. Return object by value
class Base {
public:
int i;
int* ip;
Base(){}
ip = new int;
*ip = *(rhs.ip);
}
i = rhs.i;
caveats :
1. We must ensure that the memory is big enough/valid
2. We must ensure that the memory is aligned
3. We must ensure that the memory is deallocated (call dtor explicitly . Even placement
delete is useless here since it’s for different purpose)
** placement delete :
Placement delete is not supposed to be called directly by the user .Rather, it merely
serves as the deacllocation function that the implementation must invoke when an
exception occurs during the construction of an object by placement new. To generalize,
for every version of operator new, C++ provides a matching operator delete. Since there
are six versions of operator new (ordinary new, placement new, nothrow new, as well as
their array counterparts), there are also six corresponding versions of delete.
As opposed to a common belief, placement delete does not invoke the destructor of its
argument; in fact, it has no effect. To ensure that an object constructed by placement new
is destructed, you need to call its destructor explicitly.
** Prefer Prefix operator since in the postfix case, the value is increased, but the old
value is returned. So one extra temp is created.
Prefer += instead of + <same reason,temp avoid>
class B
{
public:
B(int x = 0) : mx(x){cout << "1";}
B(const B& rhs){cout << "2"; mx = rhs.mx;}
B& operator=(const B& rhs)
{cout << "3"; if(this == &rhs) return *this; mx = rhs.mx; return *this;}
operator int(){cout << "4"; return B::mx ;}
~B(){cout << "5";}
private:
int mx;
};
int main()
{
B b;
b = 2 + b;
return 0;
}
**When a class overloads operator new and delete, these have to be static. This is
because these operators are called before the object is create and after it has been
destroyed respectively.
Alternatively it makes sense to think that these operators know how to new and delete
objects of a given class rather than on a "per object" basis. "
** "It is important to remember that if the base class overloads operator new and operator
delete, the same will be called when creating objects of derived class also. In this case the
sizeof(B) is 8. Hence A::operator new is called with size 8 while allocating p. When p is
destroyed, A::operator delete is called with the size parameter as 4. This is because A has
not defined it's destructor as virtual. Modify this code and make the destructor as virtual
and check the program output. Calls to operator new and operator delete for p1 are as
expected."
---------
What is your opinion on the code below?
class A
{
public:
virtual A& print(){cout << "1"; return *this;}
void fn(){cout << "2";}
};
class B : public A
{
public:
A& print(){cout << "3"; return static_cast<A&>(*this);}
void fn(){cout << "4";}
};
class C: public A
{
B& print(){static B b; cout << "5"; return b;}
};
int main()
{
C c;
A &aref = c;
aref.print();
B b;
A &aref2 = b;
aref2.print();
aref2.fn();
return 0;
}
a)This code will give compilation error as the overloaded functions differ only in their return type
b)This code will print 532
c)This code will print 332
d)This code will print 534
Sorry, the correct answer is b. Remember that the only exceptional case in which
virtual functions signature can be different in the derived class is if the return type
of the base class (virtual) function is a public base class of the return type of the
derived class function. In this case, even if the function signatures are different, they are
still treated as polymorphic. That is the reason aref.print call is routed to C::print rather
than A::print. Also note that C::print is private. However since the call to C::print is
routed via the VTABLE the access restriction does not hold good in this case, and the
private function is called.
**Virtual inheritance:
Mechanism whereby a class specifies that it is willing to share the state of its virtual base
class. Under virtual inheritance, only one, shared base-class subobject is inherited for a
given virtual base regardless of how many times the class occurs as a virtual base within
the derivation hierarchy. The shared base-class subobject is called a virtual base class.
Ordinarily each class initializes only its own direct base class(es). This initialization
strategy fails when applied to a virtual base class. If the normal rules were used, then the
virtual base might be initialized multiple times. The class would be initialized along each
inheritance path that contains the virtual base. To solve this duplicate-initialization
problem, classes that inherit from a class that has a virtual base have special
handling for initialization. In a virtual derivation, the virtual base is initialized by
the most derived constructor.
Although the virtual base is initialized by the most derived class, any classes that inherit
immediately or indirectly from the virtual base usually also have to provide their own
initializers for that base. As long as we can create independent objects of a type derived
from a virtual base, that class must initialize its virtual base. These initializers are used
only when we create objects of the intermediate type.
Another important thing to remember is that virtual base classes are always
constructed prior to non-virtual base classes regardless of where they appear in the
inheritance hierarchy.
Examples of virtual inheritance are plenty in the standard library. istream and
ostream virtually inherit from ios. iostream multiply inherits from istream and
ostream.
class Base {
public:
int i;
Base(int a) {cout<<"1"<<endl;
i = a;}
};
Der1(int a):Base(a){cout<<"2"<<endl;}
};
Der2(int a):Base(a){cout<<"3"<<endl;}
};
};
};
int main()
{
Der1 d(11);
cout<<d.i<<endl; Base::i = 11
D d(1,2,3,99);
cout<<d.i<<endl; Base::i = 99
cin.get();
return 0;
}
** Templates: On demand, New code for every new type (but just one for one type)
From the point of view of the compiler, templates are not normal functions or classes.
They are compiled on demand, meaning that the code of a template function is not
compiled until an instantiation with specific template arguments is required. At that
moment, when an instantiation is required, the compiler generates a function specifically
for those arguments (argument types to be precise) from the template.
Thus might lead to code bloat if used indiscriminately.
Better than macros,for sure.
Same behaviour for all/diff data types : prefer Templates ex : multiply() for diff types
Diff behaviour and/or diff data types : prefer Inheritance ex: Shape hierarchy draw()
Template class can have both templatized and non-templatized member functions.
Remember that non type parameters of a template are not L-values. They can not
be modified inside the class. “Const”
Static member variables of a class template are shared across all instantiations of a
given type. This means that objects of type Foo<int> will all share the same static
member, whereas objects of type Foo<double> will all share the same static
member, which is different from the static member of type Foo<int>
---
A dependent name is a name that depends on the type or the value of a template
parameter.
Dependent names technically exist outside of template definitions as well, but most
discussion of dependent names involves the need for disambiguation of dependent names
within template definitions.
The compiler binds dependent names when a template is instantiated. The compiler binds
non-dependent names when a template is defined
Ex:
template<class T> class U : A<T>
{
typename T::B x;
void f(A<T>& y)
{
*y++;
}
}; // The dependent names in this example are the base class A<T>,
// the type name T::B, and the variable y.
--------
typename keyword:
rules :
2 uses:
1. Interchangeable with class keyword in template declaration
2. To inform compiler that the name used in template declaration is a type name and not
an object name. ex: typename X::Name someObject;
i.e, typename T::iterator * iter;
since, otherwise this might get parsed as object name and not type name (if there is such a
object in scope) and lead to compile error,
class ContainsAType {
class iterator { ... }:
...
};
class ContainsAValue {
static int iterator;
};
template<>
void sort<char*>(Array<char*>&); Function Template
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {return ++element;}
};
int main () {
mycontainer<int> myint (7);
mycontainer<char> mychar ('j');
cout << myint.increase() << endl;
cout << mychar.uppercase() << endl; return 0;}
Disadv:
1. Since the compiler generates additional code for each template type (or, class for
a type), indiscriminate use of templates can lead to code bloat, resulting in larger
executables.
2. Still some compilers don’t have standard support for templates.
3. Can’t have them distributed as libraries.All the impl code mite desirably be in
headers since they are not concrete functions/classes but generic ones/patterns.
(In order for the compiler to generate the code, it must see both the template
definition (not just declaration) and the specific types/whatever used to "fill in"
the template. For example, if you're trying to use a Foo<int>, the compiler must
see both the Foo template and the fact that you're trying to make a specific
Foo<int>)
2 aproaches :
1. Inclusion Model : put def in header itself, code bloat but cleaner
2. Explicit Instantiation : Put directive in .cpp file. This avoids code bloat but
it’s a manual approach
#include "myfirst.cpp"
// explicitly instantiate print_typeof() for type double
template void print_typeof<double>(double const&);
-----------------------------------------------------------------------------------
** Returning ptr/ reference from a func, problems :
1. If you have local data in a function, you really ought not return a reference to it at all
(unless it is static) since it will be be a reference to memory that is no longer valid.
2. You are returning a reference to member data of an object. Although returning a const
reference prevents anyone from changing the data by using it, it means that you have to
have persistent data to back the reference--it has to actually be a field of the object and
not temporary data created in the function
3. if its ref/ptr to const, then it can be assigned to anything non-const so this wont work :
public:
MyClass(int nVal = 0) : m_nVal(nVal){
}
MyClass& operator++(){
cout << "In operator++()" << endl;
m_nVal++;
return *this;
}
MyClass operator++(int){
cout << "In operator++(int)" << endl;
MyClass ret(*this);
++*this;
return ret;
}
};
int main(){
MyClass cls(0);
cls++;
++cls;
return 0;
}
c) In operator++(int)
In Copy Constructor
In operator++()
In operator++()
1. composition:
class HoldsAnInt {
private:
int x;
Empty e; // should require no memory
};
2. Private inheritance
int x;
};
sizeof(HoldsAnInt) = sizeof(int)
7. CCtor in derived class to handle base class types copy -> POSSIBLE !!
Ex:
class A
{
public:
A(int n = 0) : mnA(n){}
A(const A& rhs){mnA = rhs.mnA;}
A& operator=(const A& rhs)
{if(&rhs == this) return *this; mnA = rhs.mnA; return *this; }
virtual ~A(){}
protected:
int mnA;
};
class C: public A
{
public:
C(int n = 0) : mnC(n), A(n){}
C(const C& rhs){mnC = rhs.mnC;}
C& operator=(const C& rhs)
{if(&rhs == this) return *this; mnC = rhs.mnC; return *this;}
C& operator=(const A& rhs)
{if(&rhs == this) return *this; (A&)(*this) = rhs; return *this;}
void print()
{cout << A::mnA << mnC;}
virtual ~C(){}
private:
int mnC; };
int main()
{
C c(2);
C c2(c);
C c3;
C c4;
A a(2);
c3 = c;
c4 = a;
c.print();
c2.print();
c3.print();
c4.print();
return 0; } o/p : 22 02 02 20 if we had not given CCtor/Ass Op then
compiler would have done bit wise copy and
o/p : 22 22 22 2
Sorry, the correct answer is b. "It is important to note that the derived class assignment
operator and the copy constructor should take care of base class members also. That does
not happen automatically. In this case there are two assignment operators in class C. The
assignment operator which takes const C& does not take care of base class assignment.
c2 is copy initialized from c through the copy constructor of C which does not take care
of base class member. Hence c2.print() prints 02.
Note that had we not declared our own copy constructor the compiler synthesized copy
constructor would have initialised the base class members also (bit wise copy).
c3 is assigned to c and this involves the operator=(const C&). This also does not take care
of the base class members. Hence this also prints 02.
Finally c4.print() prints 20. This is because this assignment invokes operator=(const A&)
and this takes care only of the base class member.
Main(){
B b = 1; // Else these 2 lines won’t compile at all
Or B b; b = 2;
}
11. temp t; temp y = t; -> calls CCtor not Ass oprtr (obviously)
12. in Cctor and assnmnt op : not necc to have params as const&
13. We must return *this in overloaded ass op otherwise normal assigmnt wud work but
chain of assignment will/might fail espclly if we return void.
14. If you do not specify your own set_new_handler() function, new throws an
exception of type std::bad_alloc.
15. Avoid overloading on a pointer and a numerical type.
16. Avoid data members in the public interface.Since functions are a better/flexible
abstraction.
** Absurdities in C++:
1. Virtual cTor : 1. Trying to call derived version of ctor using existing base ptr to
derived object. Non sense !! still wanna do -> factory method pattern.
2. virtual Static func : since static is class scope and mutually exclusive from virtual func
concept.
3. virtual friend func : But approx would be like :
class CPerson
{
friend ostream &operator<< (ostream &out, CPerson &person);
// ...
protected:
virtual ostream &display(ostream &out);
// ...
};
The friend function forwards the display request back to the CPerson class. Note that we
pass an instance of CPerson by reference:
In a class hierarchy using the base CPerson class, each derived class has its own
implementation of the display function:
**
class Shape {
public:
int main()
{
Shape* cp;
cp -> create(); run time error !! since virtual funcns are object associated unlike
plain/static funcns
}
------
Overload iostream ops :
2. Stack Only :
class autoOnly
{
public:
autoOnly()
{
;
}
~autoOnly()
{
;
}
private:
void* operator new(size_t)
{
// Dummy Implementation
}
3. Heap Only : (caveat : give func for delete, its lets on heap !!!)
class HeapOnly
{
public:
void DestroyMe() //This function will call destructor
{
delete this; // Current object will be deleted means destructor
}
private:
~HeapOnly(); // destructor only can be call by member function
};
main()
{
HeapOnly* h = new HeapOnly(); // fine
HeapOnly h; // error !!
}
class temp
{
private:
~temp() {; }
friend class Final; // Due to friend , Final class can use private
member functions of temp class
};
class Final: virtual public temp // if not virtual inheritance then
// still Child can be derived from
// Final as a heap only class
{
// Define all data members and functions as you want
public:
Final()
{
;
}
~Final();
};
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
virtual void draw() = 0; // A pure virtual function
virtual void move() = 0;
.. .
virtual Shape* clone() const = 0; // Uses the copy constructor
virtual Shape* create() const = 0; // Uses the default constructor
};
void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};
int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}
** AutoPtr Class
template<class T>
class auto_ptr {
private:
T* ap; // refers to the actual owned object (if any)
public:
typedef T element_type;
// constructor
explicit auto_ptr (T* ptr = 0) throw()
: ap(ptr) {
}
template<class Y>
auto_ptr& operator= (auto_ptr<Y>& rhs) throw() {
reset(rhs.release());
return *this;
}
// destructor
~auto_ptr() throw() {
delete ap;
}
// value access
T* get() const throw() {
return ap;
}
T& operator*() const throw() {
return *ap;
}
T* operator->() const throw() {
return ap;
}
// release ownership
T* release() throw() {
T* tmp(ap);
ap = 0;
return tmp;
}
// reset value
void reset (T* ptr=0) throw() {
if (ap != ptr) {
delete ap;
ap = ptr;
}
}
template<class Y>
operator auto_ptr_ref<Y>() throw() {
return auto_ptr_ref<Y>(release());
}
template<class Y>
operator auto_ptr<Y>() throw() {
return auto_ptr<Y>(release());
}
};
}
-------------------------------------------------------------------------------
class Pointer
{
public:
~Pointer (void){
cout<<"Pointer::Destructor\n";
}
//accessor
unsigned int count(void){
cout<<"Reference count value is ="<<refCount_<<"\n";
return (refCount_); //return current count
}
private:
//data
int myVal_;
unsigned int refCount_; // reference counting related data
}; // Pointer
class SmartPointer {
public:
ptr_->acquire();
return(*this);
}
}
~SmartPointer (void){
cout<<"SmartPointer::Destructor\n";
if (NULL != ptr_)
{ if (0 == ptr_->release())
{
ptr_->count();
delete(ptr_);
ptr_ = NULL;
}
}
}
private:
Pointer * ptr_;
}; // SmartPointer
return(0);
}