Thứ Ba, 2 tháng 4, 2019

[Học C++] Bài9 - Tham chiếu trong C++

1. Giới thiệu

int* first (int* x)
{
    (*x++);
    return x;   // SAFE, x is outside this scope
}
int& second (int& x)
{
    x++;
    return x;   // SAFE, x is outside this scope
}
int& third ()
{
    int q;
    return q;   // ERROR, scope of q ends here
}
int& fourth ()
{
    static int x;
    return x;   // SAFE, x is static, hence lives till the end.
}
int main()
{
    int a=0;
    first(&a);   // UGLY and explicit
    second(a);   // CLEAN and hidden
}
We have four different functions in the above program.
first() takes a pointer as argument and returns a pointer, it will work fine. The returning pointer points to variable declared outside first(), hence it will be valid even after the first() ends.
Similarly, second() will also work fine. The returning reference is connected to valid storage, that is int a in this case.
But in case of third(), we declare a variable q inside the function and try to return a reference connected to it. But as soon as function third() ends, the local variable q is destroyed, hence nothing is returned.
To remedify above problem, we make x as static in function fourth(), giving it a lifetime till main() ends, hence now a reference connected to x will be valid when returned.

2. Const Reference
Sử dụng làm tham chiếu cho hàm tránh việc bị thay đổi giá trị tham số.
Ví dụ
void g(const int& x)
{
    x++;
}   // ERROR
int main()
{
    int i=10;
    g(i);
}
Chúng ta không thể thay đổi đối số trong hàm vì nó đã được truyền như 1 hằng tham chiếu.
Khi ta sử dụng const reference,chỉ 1 địa chỉ được truyền vào trên stack,cái được sử dụng bên
trong hàm và hàm không thể thay đổi đối số vì nó là 1 hằng.

3. mutable Keyword
mutable keyword is used with member variables of class, which we want to change even if the object is of const type. Hence, mutable data members of a const objects can be modified.
class Zee
{
    int i;
    mutable int j;
    public:
    Zee()
    {
        i = 0;
        j = 0;
    }
   
    void fool() const
    {
        i++;    // will give error
        j++;    // works, because j is mutable
    }
};
int main()
{
    const Zee obj;
    obj.fool();
}

[Học C++] Bài8 - Inline Functions và Function Overloading trong C++

Inline function là gì?

Nó có tính chất khá tương tự như Preprocessors trong C.
Hàm Inline thực chất là 1 hàm,.nó là bản copy của hàm trong quá trình biên dịch...
Tất cả các members bên trong class được mặc định định nghĩa như 1 Inline.Do đó không cần khai báo
từ khóa Inline,nhưng để cho clear chúng ta có thể thêm...
inline void fun(int a)
{
    return a++;
}

1 . Forward References trong C++
Vì Inline function trong 1 class được đánh giá đến khi kết thúc class "};"
Ví dụ sau sẽ rõ:
class ForwardReference
{
    int i;
    public:
    // call to undeclared function
    int f() //f là 1 inline function
    {
        return g()+10;
    }
    int g() //g là 1 inline function
    {
        return i;
    }
};
int main()
{
    ForwardReference fr;
    fr.f();
}
Nhiều bạn nghĩ program sẽ lỗi...Nhưng không hề lỗi.
Hàm Inline trong class: Các hàm định nghĩa ở trên có thể gọi các hàm ở line dưới.
Vì class chỉ được định nghĩa khi nó kết thúc khỏi dấu "};" Do đó tất cả các hàm trong
class đều được định nghĩa.

Kinh nghiệm:

- Tạo hàm Inline nhỏ và có ít tham số sẽ tốt hơn.
- Inline function sẽ tăng tính hiệu quả,nhưng không nên tạo tất cả là hàm Inline.
Vì khi có quá nhiều hàm Inline nó dẫn đến code bloat,Cache missing và ảnh hưởng tới speed.
- Lời khuyên là: Nên định nghĩa các hàm lớn bên ngoài class,sử dụng "::" để gọi.
- Inline function không yêu cầu cấp bộ nhớ cho nó mà nó được giữ tại Symbol table..Do đó
khi ta thực hiện tác vụ là yêu cầu địa chỉ của Inline function,Compiler không thể thực hiện
quá trình inlining như 1 hàm binhg thường.Bởi vì,để cung cấp địa chỉ cho 1 hàm bất kì,Compiler sẽ phải
cấp phát bộ nhớ cho nó.


Nếu class có nhiều hàm và các hàm trùng tên nhau..
Chú ý,Overloading không phải đệ quy--- Đệ quy là 1 hàm và trong thân hàm gọi lại chính nó...
Còn Overloading là các hàm với các kiểu trả về,tham số khác nhau,hay đặc biệt là giống nhau nhưng cùng tên.



2. Có 2 cách tạo Overloading function
2.1 Khác số lượng tham số

// first definition có 2 tham số x,y
int sum (int x, int y)
{
    cout << x+y;
}
// second overloaded defintion có 3 tham số x,y,z
int sum(int x, int y, int z)
{
    cout << x+y+z;
}

int main()
{
    // sum() with 2 parameter will be called
    sum (10, 20); 
    //sum() with 3 parameter will be called
    sum(10, 20, 30); 
}


2.2 Khác kiểu trả về
int sum(int x, int y)
{
    cout<< x+y;
}
// second overloaded defintion
double sum(double x, double y)
{
    cout << x+y;
}
int main()
{
    sum (10,20);
    sum(10.5,20.5);
}
2.3 Hàm với tham số mặc định
sum(int x, int y=0)
{
    cout << x+y;
}
int main()
{
    sum(10);
    sum(10,0);
    sum(10,10);
}
OUTPUT 10 10 20

Một số rule:
- Chỉ tham số cuối cùng mới được làm default argument
sum (int x,int y);   
sum (int x,int y=0); 
sum (int x=0,int y);  // This is Incorrect
void f(int a,int b=0,int c) {}  //sai
Vậy muốn dùng nhiều default parameters???
void f(int a,int b=0,int c=0) {} // Để dùng default thì ra phải set value cho
tất cả các tham số sau tham số đầu tiên.

Ngoài ta,ta cũng có thể không cần khai báo tham số mà chỉ cần khai báo kiểu dữ liệu
void sum (int, int);
void sum (int, int=0);
void main() {
 sum(8,8); //ok
 sum(7.6,9); // vẫn ok. Nhưng hãy cẩn thận đến range của đối số,có thể kết quả sẽ sai
}


Thứ Hai, 1 tháng 4, 2019

[Học C++] Bài8 - Lớp lưu trữ trong C++

Lớp lưu trữ (Storage Class) định nghĩa phạm vi và vòng đời của biến và/hoặc các hàm bên trong một chương trình C/C++. Chúng thường đứng trước kiểu dữ liệu mà chúng tác động. Dưới đây là các lớp lưu trữ có thể được sử dụng trong C/C++:
auto
register
static
extern
mutable

3 . Lớp lưu trữ static trong C/C++
Lớp lưu trữ static trong C/C++ nói với compiler để giữ một biến cục bộ tồn tại trong toàn bộ thời gian sống của chương trình thay vì tạo và hủy biến mỗi lần nó vào và ra khỏi phạm vi biến. Vì vậy, các biến có static cho phép nó duy trì giá trị giữa các lần gọi hàm.
Lớp lưu trữ static cũng có thể được áp dụng cho các biến toàn cục (global). Khi áp dụng cho biến toàn cục, nó nói với trình biên dịch rằng, phạm vi của biến toàn cục bị giới hạn trong tập tin mà nó được khai báo.
Trong C/C++, khi static được sử dụng trên thành viên dữ liệu của lớp, nó gây ra: chỉ có một bản sao của thành viên đó được chia sẻ bởi tất cả đối tượng trong lớp của nó.
#include <iostream>

// phan khai bao ham
void func(void);

static int biendem = 10; /* Day la bien toan cuc */

main()
{
    while(biendem--)
    {
       func();
    }
    return 0;
}
// Phan dinh nghia ham
void func( void )
{
    static int i = 5; // Day la bien cuc bo dang static
    i++;
    std::cout << "i co gia tri la " << i ;
    std::cout << " va biendem co gia tri la " << biendem << std::endl;
}

Lớp lưu trữ static trong C/C++

Code C hay sử dụng trong lập trình nhúng - Embedded C

1. include và preprocessor

2. Macro và biến

. Qualifier trong C
Qualifier cung cấp thông tin bổ sung về các biến theo sau nó.

- const : Đối tượng của kiểu const không thể bị thay đổi bởi chương trình trong khi thực thi
- volatile: Modifier này nói cho compiler rằng giá trị của biến có thể được thay đổi một cách không rõ ràng (không báo trước) bởi chương trình.

3. Struct
Struct được sử dụng rất nhiều trong lập trình nhúng.

Ví dụ như khai báo 2 kiểu trạng thái 0,1
struct State {
     bool GPIO_SET 1;
     bool GPIO_RESET 0;
}sts;


4. Hàm
- Hàm quan trọng nhất trong lập trình nhúng:
while(1) {
// các hàm trong này luôn được lặp mãi mãi,cho đến khi chương trình dừng hẳn thì thôi
}

while(0) {
// Không thực thi bất kì câu lệnh nào trong này.
}

5. Con trỏ


6. Các từ khóa và kiểu dữ liệu