CONST
const int p và int const p là như nhau
int* const p nghĩa là một hằng số loại con trỏ mà trỏ đến một biến số kiểu nguyên, nghĩa là bạn không thể thay đổi để con trỏ này trỏ đến một nơi khác được nữa
CODE
int a = 3;int b = 5;
int* const p = &a;
p = &b; //không hợp lệ
const int* p nghĩa là một biến số loại con trỏ mà trỏ đến một hằng số kiểu nguyên, nghĩa là bạn có thể thay đổi để con trỏ này trỏ đến một nơi khác, nhưng không thể thay đổi dữ liệu ở nơi nó trỏ đến
CODE
int a = 3;int b = 5;
const int* p = &a;
p = &b; //hợp lệ
*p = 6; //không hợp lệ
const int *& p nghĩa là một tham chiếu mà tham chiếu tới một biến số loại con trỏ mà trỏ đến một hằng số kiểu nguyên
int const *& p nghĩa là một tham chiếu mà tham chiếu tới một hằng số loại con trỏ mà trỏ đến một biến số kiểu nguyên
Một biến số const nghĩa là biến đó phải được gán giá trị ngay lúc khai báo và giá trị ấy vĩnh viễn không thay đổi (cái này quá phổ biến rồi)
Một hàm số const nghĩa là hàm số đó sẽ không thay đổi giá trị của bất cứ tham số nào của nó. Một hàm số phải được khai báo const nếu nó có ít nhất một tham số const
CODE
class Tree{
int age;
public:int getAge() const{return age;}
friend ostream& operator<<(ostream& os,const Tree& t)
{os<<t.getAge();return os;}
};
Hàm số getAge phải là một hàm số const để bất kì hàm số khác dùng tham số const Tree có thể sử dụng hàm số getAge
Hàm số trả về const
Ví dụ chúng ta viết một hàm như sau
CODE
int& hello()
{
int temp=5;
return temp;
}
Và một ai đó có thể lợi dụng để gán giá trị cho nó, rất nguy hiểm
CODE
hello() = 3;
Nên chúng ta phải thay đổi để nó trả về const
CODE
const int& hello()
{
int temp=5;
return temp;
}
Bảo vệ tham số
Hẳn bạn còn nhớ ví dụ này chứ
CODE
void add10(int *a){
*a=*a+10;
}
add10(&n);
Ý nghĩa ở đây là, một hàm hoàn toàn có thể thay đổi giá trị của tham số nếu ta truyền vào nó địa chỉ của biến đó. Mà việc truyền
địa chỉ là việc phải làm. Vì đôi khi không thể không truyền địa chỉ, ví dụ kiểu mảng
CODE
void dosomething(char* a){...}
char* m = "hello";
dosomething(m);
Khi đó ta dùng từ khóa const để ngăn việc hàm thay đổi giá trị của đối số
CODE
void dosomething(const char* a){...}
char* m = "hello";
dosomething(m);
--------------------------------------------------------------------------------
STATIC
Một biến số const nghĩa là biến đó phải được gán giá trị ngay lúc khai báo và giá trị ấy vĩnh viễn không thay đổi
Một biến số static nghĩa là biến đó phải được gán giá trị ngay trước khi tạo một instance của một lớp và giá trị ấy được thay đổi,
nhưng chỉ có duy nhất một biến static ấy tồn tại đối với tất cả instance của lớp đó
CODE
class MyClass
{
public:
static int i;
};
int MyClass::i; //tồn tại độc lập, không phụ thuộc instance
int main()
{
MyClass::i=30;
MyClass x,y;
x.i=26;
cout<<y.i<<endl;
}
Một hàm số static nghĩa là hàm số ấy có thể độc hoạt động lập mà không cần tạo đối tượng của lớp
CODE
class MyClass
{
public:
static void print(char* s)
{
cout<<s<<endl;
}
};
int main()
{
MyClass::p("Hello");
return 0;
}
----------------------------------------------------------------------------
Ngoại lệ (Exception)
Hàm dưới đây có thể ném ra bất cứ ngoại lệ nào
CODE
void in(int a); //chỉ cần khai báo bình thường
Hàm dưới đây không thể ném ra bất cứ ngoại lệ nào
CODE
void in(int a) throw();
Không như Java, trong C++ bất cứ lớp nào cũng có thể là lớp ngoại lệ (exception class), và cũng không cần phải là lớp con của lớp
nào hết
Chúng ta bắt ngoại lệ bằng try catch như Java
CODE
class DivideByZero
{
public:
void msg()
{
cout<<"Can not divide by zero"<<endl;
}
};
int divide(int a,int b) throw(DivideByZero)
{
if(b==0) throw DivideByZero();
return a/b;
}
int main()
{
try
{
int a=divide(3,0);
}
catch(DivideByZero e)
{
e.msg();
}
return 0;
}
Khi chúng ta bắt được một ngoại lệ, chúng ta có thể ném nó ra để bắt lại một lần nữa bằng throw;
CODE
class DivideByZero
{
public:
void msg()
{
cout<<"Can not divide by zero"<<endl;
}
};
int divide(int a,int b) throw(DivideByZero)
{
if(b==0) throw DivideByZero();
return a/b;
}
int main()
{
try
{
try
{
int a=divide(3,0);
}
catch(DivideByZero e)
{
e.msg();throw; //ném ra để bắt lại lần hai
}
}
catch(DivideByZero)
{
cout<<"Stopped! That's enough"<<endl;
}
return 0;
}
Chúng ta có thể ném ra và bắt lại bất cứ cái gì chứ không phải chỉ một lớp
CODE
int main()
{
int s[5];
try
{
for(int i=0;i<6;i++)
{
if(i>=5) throw "Out of range";
s[i] = i;
}
}
catch(char* c)
{
cout<<c<<endl;
}
return 0;
}
Chúng ta có thể ném ra nhiều thứ bằng một chỉ thị try và bắt lại tất cả mọi thứ, mỗi thứ một chỉ thị catch khác nhau
CODE
int main()
{
try
{
int size;cin>>size;
if(size>10) throw "So big";
else throw size;
}
catch(int n)
{
cout<<n<<" is not here"<<endl;
}
catch(char* c)
{
cout<<c<<endl;
}
return 0;
} N
ếu có ngoại lệ nào không bị bắt, hàm đặc biệt void terminate() sẽ được gọi ngay lập tức để chấm dứt chương trình
Chúng ta có thể bắt tất cả các loại ngoại lệ để xử lí chỉ với một chỉ thị catch(...)
CODE
int main()
{
try
{
int size;cin>>size;
if(size>10) throw "So big";
else throw size;
}
catch(...)
{
cout<<"throw exception"<<endl;
}
return 0;
}
----------------------------------------------------------------------------
Ép kiểu (Casting)
Ép kiểu theo cách của C
int n=(int)45.87;
static_cast (ép kiểu tĩnh)
Kiểm tra lúc biên dịch (compile time)
int n=static_cast<int>(45.87);
int n=static_cast<int>(“hello”); //lúc biên dịch sẽ phát sinh lỗi
dynamic_cast (ép kiểu động)
Kiểm tra lúc thực thi (runtime) Lớp dùng với dynamic_cast phải có hàm ảo.
downcast
Ép kiểu các con trỏ và các đối tượng từ kiểu lớp cha thành kiểu lớp con, được gọi là downcast. Đây là một kiểu casting quan trọng, dùng nhiều về sau trong RTTI. Có 2 cách thực hiện downcast
bằng static_cast
CODE
class Base{};
class Derived : public Base{};
Base* b=new Derived;
Derived* d = static_cast<Derived*>(b);
bằng dynamic_cast
CODE
class Base{virtual void func(){}};
class Derived : public Base{};
Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b);
upcast
Ép kiểu các con trỏ và các đối tượng từ kiểu lớp con thành kiểu lớp cha, được gọi là upcast. upcast hiếm dùng hơn downcast. Có 2 cách thực hiện upcast
bằng static_cast
CODE
class Base{};
class Derived : public Base{};
Derived* d = new Derived;
Base* b = static_cast<Base*>(d);
bằng dynamic_cast
CODE
class Base{virtual void func(){}};
class Derived : public Base{};
Derived* d = new Derived;
Base* b = dynamic_cast<Base*>(d);
const_cast (ép kiểu hằng)
const_cast dùng chủ yếu với các con trỏ
const_cast dùng để thay đổi một biến số thành một hằng số (thêm từ khóa const vào)
CODE
int a=3;
int* b=&a;
*b = 8;//hợp lệ
const int* c=const_cast<int*>(b);
*c=5; //không hợp lệ
cout<<*c;
cout<<a;
const_cast dùng để thay đổi một hằng số thành một biến số (gỡ từ khóa const ra)
CODE
const int a=3;
const int* b=&a;
*b = 8; //không hợp lệ
int* c=const_cast<int*>(b);
*c=5; //hợp lệ
cout<<*c;
cout<<a;
reinterpret_cast (ép kiểu thông dịch lại)
reinterpret_cast sẽ ép kiểu bất cứ con trỏ hay đối tượng nào mà không hề có sự kiểm tra nào cả. Không khuyến khích dùng và bây giờ ta cũng chưa phải dùng, sẽ học sau.
Thứ Tư, 8 tháng 6, 2016
Đăng ký:
Đăng Nhận xét (Atom)
0 nhận xét:
Đăng nhận xét