constructor/deconstructor:
[review points]:
1) several type of constructors:
1) several type of constructors:
default constructor
parameterized constructor
copy constructor
how are these constructors got called?
2) why virtual deconstructor?
how are these constructors got called?
2) why virtual deconstructor?
[code] class Base{ private: int member; public: Base(void) = default; Base(int v):member(v){}; Base(const Base &b) { member = b.member; } Base &operator= (const Base &b) { member = b.member; return *this; } virtual ~Base(void){} };
inheritence:
[review points]:
type casts:
static_cast
static_cast is used for cases where you basically want to reverse an implicit conversion, with a few restrictions and additions. static_cast performs no runtime checks. This should be used if you know that you refer to an object of a specific type, and thus a check would be unnecessary.
Example:
void func(void *data) {
// Conversion from MyClass* -> void* is implicit
MyClass *c = static_cast<MyClass*>(data);
...
}
int main() {
MyClass c;
start_thread(&func, &c) // func(&c) will be called
.join();
}
In this example, you know that you passed a MyClass object, and thus there isn't any need for a runtime check to ensure this.
dynamic_cast
dynamic_cast is used for cases where you don't know what the dynamic type of the object is. You cannot use dynamic_cast if you downcast and the argument type is not polymorphic. An example:
if(JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
...
} else if(ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
...
}
dynamic_cast returns a null pointer if the object referred to doesn't contain the type casted to as a base class (when you cast to a reference, a bad_cast exception is thrown in that case).
The following code is not valid, because Base is not polymorphic (it doesn't contain a virtual function):
struct Base { };
struct Derived : Base { };
int main() {
Derived d; Base *b = &d;
dynamic_cast<Derived*>(b); // Invalid
}
An "up-cast" is always valid with both static_cast and dynamic_cast, and also without any cast, as an "up-cast" is an implicit conversion.
Regular Cast
These casts are also called C-style cast. A C-style cast is basically identical to trying out a range of sequences of C++ casts, and taking the first C++ cast that works, without ever considering dynamic_cast. Needless to say, this is much more powerful as it combines all of const_cast, static_cast and reinterpret_cast, but it's also unsafe, because it does not use dynamic_cast.
In addition, C-style casts not only allow you to do this, but they also allow you to safely cast to a private base-class, while the "equivalent" static_cast sequence would give you a compile-time error for that.
Some people prefer C-style casts because of their brevity. I use them for numeric casts only, and use the appropriate C++ casts when user defined types are involved, as they provide stricter checking.
const cast
This one is primarily used to add or remove the const modifier of a variable.
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
Although const cast allows the value of a constant to be changed, doing so is still invalid code that may cause a run-time error. This could occur for example if the constant was located in a section of read-only memory.
*nonConst = 10; // potential run-time error
Const cast is instead used mainly when there is a function that takes a non-constant pointer argument, even though it does not modify the pointee.
void print(int *p)
{
std::cout << *p;
}
The function can then be passed a constant variable by using a const cast.
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
regular cast
These casts are also called C-style cast. A C-style cast is basically identical to trying out a range of sequences of C++ casts, and taking the first C++ cast that works, without ever considering dynamic_cast. Needless to say, this is much more powerful as it combines all of const_cast, static_cast and reinterpret_cast, but it's also unsafe, because it does not use dynamic_cast.In addition, C-style casts not only allow you to do this, but they also allow you to safely cast to a private base-class, while the "equivalent" static_cast sequence would give you a compile-time error for that.Some people prefer C-style casts because of their brevity. I use them for numeric casts only, and use the appropriate C++ casts when user defined types are involved, as they provide stricter checking.
operator overload:
class Complex {
private:
int _a, _b;
public:
Complex(int a=0, int b=0):_a(a),_b(b){};
// 1. over loading syntax
const Complex operator + (const Complex &c)
{
return Complex(_a+c._a, _b+c._b);
}
Complex & operator += (const Complex &c)
{
_a += c._a;
_b += c._b;
return *this;
}
// 2. unary operator overloading
const Complex operator -() const
{
return Complex(-_a, -_b);
}
const Complex operator ++()
{
return Complex(++_a, ++_b);
}
const Complex operator ++(int)
{
return Complex(_a++, _b++);
}
const Complex operator --()
{
return Complex(--_a, --_b);
}
const Complex operator --(int)
{
return Complex(_a--, _b--);
}
// 3. binary operator overloading
friend const Complex operator +( const Complex &left, const Complex &right)
{
return Complex(left._a + right._a, left._b + right._b);
}
// 4. iostream overloading
friend ostream & operator << ( ostream &os, const Complex &c)
{
os << "Complex:" << c._a <<"+" << c._b << endl;
return os;
}
#if 0
friend istream &operator >> ( istream &is, Complex &c)
{
is >> c._a >> c._b;
return is;
}
#endif
friend istream &operator >> (istream &is, Complex &c)
{
string mystr;
cout << "first ele";
getline(is, mystr);
stringstream(mystr) >> c._a;
cout << "second ele";
getline(is, mystr);
stringstream(mystr) >> c._b;
return is;
}
};
private:
int _a, _b;
public:
Complex(int a=0, int b=0):_a(a),_b(b){};
// 1. over loading syntax
const Complex operator + (const Complex &c)
{
return Complex(_a+c._a, _b+c._b);
}
Complex & operator += (const Complex &c)
{
_a += c._a;
_b += c._b;
return *this;
}
// 2. unary operator overloading
const Complex operator -() const
{
return Complex(-_a, -_b);
}
const Complex operator ++()
{
return Complex(++_a, ++_b);
}
const Complex operator ++(int)
{
return Complex(_a++, _b++);
}
const Complex operator --()
{
return Complex(--_a, --_b);
}
const Complex operator --(int)
{
return Complex(_a--, _b--);
}
// 3. binary operator overloading
friend const Complex operator +( const Complex &left, const Complex &right)
{
return Complex(left._a + right._a, left._b + right._b);
}
// 4. iostream overloading
friend ostream & operator << ( ostream &os, const Complex &c)
{
os << "Complex:" << c._a <<"+" << c._b << endl;
return os;
}
#if 0
friend istream &operator >> ( istream &is, Complex &c)
{
is >> c._a >> c._b;
return is;
}
#endif
friend istream &operator >> (istream &is, Complex &c)
{
string mystr;
cout << "first ele";
getline(is, mystr);
stringstream(mystr) >> c._a;
cout << "second ele";
getline(is, mystr);
stringstream(mystr) >> c._b;
return is;
}
};
functor
class Fctor {
private:
int m;
public:
Fctor(int x):m(x){};
int operator() (int y) { return m + y; }
};
int main(void)
{
Fctor a(10);
cout << a(20) << endl;
return 0;
}
private:
int m;
public:
Fctor(int x):m(x){};
int operator() (int y) { return m + y; }
};
int main(void)
{
Fctor a(10);
cout << a(20) << endl;
return 0;
}
smart pointer:
class TBase {
public:
TBase(void){ cout << "TBase ctor" << endl; }
void display() { cout << "Display" << endl; }
~TBase(void) { cout << "TBase dtor" << endl; }
};
void rawfunction(void)
{
TBase *tb = new TBase;
}
void scopedfunction(void)
{
unique_ptr<TBase> ptr (new TBase);
ptr -> display();
}
shared_ptr<TBase> sharedfunction(void)
{
shared_ptr<TBase>ptr (new TBase);
shared_ptr<TBase> ptr1 = ptr;
ptr ->display();
return ptr1;
}
void autofunction(void)
{
auto_ptr<TBase>ptr(new TBase);
ptr->display();
}
void weakfunction(void)
{
shared_ptr<TBase>sptr ( new TBase);
weak_ptr<TBase>ptr = sptr;
// cout << "weaked_ptr: is" << ptr << endl;
sptr->display();
}
void uniquefunction(void)
{
unique_ptr <TBase> uptr ( new TBase);
unique_ptr <TBase> wptr;
wptr = move(uptr);
wptr->display();
}
int main(void)
{
shared_ptr<TBase>ptr;
rawfunction();
cout <<"XXXXX" << endl;
scopedfunction();
cout <<"XXXXX" << endl;
ptr= sharedfunction();
cout <<"XXXXX" << endl;
autofunction();
cout <<"XXXXX" << endl;
weakfunction();
cout <<"XXXXX" << endl;
uniquefunction();
return 1;
}
template/stl
sizeof
reference
I/O
binding (c++11)
exceptions
No comments:
Post a Comment