Hướng dẫn nhanh về C ++

C ++ là một ngôn ngữ lập trình dạng tự do được định kiểu tĩnh, biên dịch, mục đích chung, phân biệt chữ hoa chữ thường, hỗ trợ lập trình thủ tục, hướng đối tượng và lập trình chung.

C ++ được coi là một middle-level ngôn ngữ, vì nó bao gồm sự kết hợp của cả các tính năng ngôn ngữ cấp cao và cấp thấp.

C ++ được phát triển bởi Bjarne Stroustrup bắt đầu từ năm 1979 tại Bell Labs ở Murray Hill, New Jersey, như một sự cải tiến cho ngôn ngữ C và ban đầu được đặt tên là C with Classes nhưng sau đó nó được đổi tên thành C ++ vào năm 1983.

C ++ là một tập hợp siêu của C và hầu như bất kỳ chương trình C hợp pháp nào cũng là một chương trình C ++ hợp pháp.

Note - Một ngôn ngữ lập trình được cho là sử dụng kiểu gõ tĩnh khi kiểm tra kiểu được thực hiện trong thời gian biên dịch thay vì thời gian chạy.

Lập trình hướng đối tượng

C ++ hỗ trợ đầy đủ lập trình hướng đối tượng, bao gồm bốn trụ cột của phát triển hướng đối tượng -

  • Encapsulation
  • Ẩn dữ liệu
  • Inheritance
  • Polymorphism

Thư viện tiêu chuẩn

C ++ tiêu chuẩn bao gồm ba phần quan trọng:

  • Ngôn ngữ cốt lõi cung cấp tất cả các khối xây dựng bao gồm các biến, kiểu dữ liệu và ký tự, v.v.

  • Thư viện tiêu chuẩn C ++ cung cấp một tập hợp các hàm phong phú thao tác với tệp, chuỗi, v.v.

  • Thư viện Mẫu Chuẩn (STL) cung cấp một tập hợp phong phú các phương pháp thao tác với cấu trúc dữ liệu, v.v.

Tiêu chuẩn ANSI

Tiêu chuẩn ANSI là một nỗ lực để đảm bảo rằng C ++ có tính di động; mã bạn viết cho trình biên dịch của Microsoft sẽ biên dịch mà không có lỗi, sử dụng trình biên dịch trên máy Mac, UNIX, hộp Windows hoặc Alpha.

Tiêu chuẩn ANSI đã ổn định trong một thời gian và tất cả các nhà sản xuất trình biên dịch C ++ lớn đều hỗ trợ tiêu chuẩn ANSI.

Học C ++

Điều quan trọng nhất trong khi học C ++ là tập trung vào các khái niệm.

Mục đích của việc học một ngôn ngữ lập trình là trở thành một lập trình viên giỏi hơn; nghĩa là, để trở nên hiệu quả hơn trong việc thiết kế và triển khai các hệ thống mới và bảo trì các hệ thống cũ.

C ++ hỗ trợ nhiều kiểu lập trình khác nhau. Bạn có thể viết theo phong cách Fortran, C, Smalltalk, v.v., bằng bất kỳ ngôn ngữ nào. Mỗi phong cách có thể đạt được mục tiêu một cách hiệu quả trong khi vẫn duy trì thời gian chạy và hiệu quả về không gian.

Sử dụng C ++

C ++ được sử dụng bởi hàng trăm nghìn lập trình viên trong mọi miền ứng dụng.

C ++ đang được sử dụng nhiều để viết trình điều khiển thiết bị và các phần mềm khác dựa vào thao tác trực tiếp với phần cứng dưới các ràng buộc thời gian thực.

C ++ được sử dụng rộng rãi cho giảng dạy và nghiên cứu vì nó đủ sạch để giảng dạy thành công các khái niệm cơ bản.

Bất kỳ ai đã sử dụng Apple Macintosh hoặc PC chạy Windows đều đã gián tiếp sử dụng C ++ vì giao diện người dùng chính của các hệ thống này được viết bằng C ++.

Thiết lập môi trường cục bộ

Nếu bạn vẫn sẵn sàng thiết lập môi trường của mình cho C ++, bạn cần có hai phần mềm sau trên máy tính của mình.

Trình soạn thảo văn bản

Điều này sẽ được sử dụng để nhập chương trình của bạn. Ví dụ về một số trình soạn thảo bao gồm Windows Notepad, lệnh Chỉnh sửa hệ điều hành, Tóm tắt, Epsilon, EMACS và vim hoặc vi.

Tên và phiên bản của trình soạn thảo văn bản có thể khác nhau trên các hệ điều hành khác nhau. Ví dụ, Notepad sẽ được sử dụng trên Windows và vim hoặc vi có thể được sử dụng trên windows cũng như Linux hoặc UNIX.

Các tệp bạn tạo bằng trình chỉnh sửa của mình được gọi là tệp nguồn và đối với C ++, chúng thường được đặt tên với phần mở rộng .cpp, .cp hoặc .c.

Một trình soạn thảo văn bản nên có sẵn để bắt đầu lập trình C ++ của bạn.

Trình biên dịch C ++

Đây là một trình biên dịch C ++ thực tế, sẽ được sử dụng để biên dịch mã nguồn của bạn thành chương trình thực thi cuối cùng.

Hầu hết các trình biên dịch C ++ không quan tâm bạn cung cấp phần mở rộng nào cho mã nguồn của mình, nhưng nếu bạn không chỉ định khác, nhiều người sẽ sử dụng .cpp theo mặc định.

Trình biên dịch miễn phí và được sử dụng thường xuyên nhất là trình biên dịch GNU C / C ++, nếu không bạn có thể có các trình biên dịch từ HP hoặc Solaris nếu bạn có Hệ điều hành tương ứng.

Cài đặt trình biên dịch GNU C / C ++

Cài đặt UNIX / Linux

Nếu bạn đang sử dụng Linux or UNIX sau đó kiểm tra xem GCC đã được cài đặt trên hệ thống của bạn hay chưa bằng cách nhập lệnh sau từ dòng lệnh:

$ g++ -v

Nếu bạn đã cài đặt GCC, thì nó sẽ in ra một thông báo như sau:

Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

Nếu GCC chưa được cài đặt, thì bạn sẽ phải tự cài đặt nó bằng cách sử dụng hướng dẫn chi tiết có tại https://gcc.gnu.org/install/

Cài đặt Mac OS X

Nếu bạn sử dụng Mac OS X, cách dễ nhất để lấy GCC là tải xuống môi trường phát triển Xcode từ trang web của Apple và làm theo hướng dẫn cài đặt đơn giản.

Xcode hiện có sẵn tại developer.apple.com/technologies/tools/ .

Cài đặt Windows

Để cài đặt GCC trên Windows, bạn cần cài đặt MinGW. Để cài đặt MinGW, hãy truy cập trang chủ MinGW, www.mingw.org , và theo liên kết đến trang tải xuống MinGW. Tải xuống phiên bản mới nhất của chương trình cài đặt MinGW sẽ được đặt tên là MinGW- <version> .exe.

Trong khi cài đặt MinGW, tối thiểu, bạn phải cài đặt gcc-core, gcc-g ++, binutils và thời gian chạy MinGW, nhưng bạn có thể muốn cài đặt thêm.

Thêm thư mục con bin của cài đặt MinGW của bạn vào PATH biến môi trường để bạn có thể chỉ định các công cụ này trên dòng lệnh bằng tên đơn giản của chúng.

Khi quá trình cài đặt hoàn tất, bạn sẽ có thể chạy gcc, g ++, ar, ranlib, dlltool và một số công cụ GNU khác từ dòng lệnh Windows.

Khi chúng ta xem xét một chương trình C ++, nó có thể được định nghĩa là một tập hợp các đối tượng giao tiếp thông qua việc gọi các phương thức của nhau. Bây giờ chúng ta hãy xem xét ngắn gọn ý nghĩa của một lớp, đối tượng, các phương thức và các biến tức thời.

  • Object- Đối tượng có trạng thái và hành vi. Ví dụ: Một con chó có các trạng thái - màu sắc, tên, giống cũng như các hành vi - vẫy tay, sủa, ăn. Một đối tượng là một thể hiện của một lớp.

  • Class - Một lớp có thể được định nghĩa như một khuôn mẫu / bản thiết kế mô tả các hành vi / trạng thái mà đối tượng kiểu của nó hỗ trợ.

  • Methods- Một phương pháp về cơ bản là một hành vi. Một lớp có thể chứa nhiều phương thức. Nó nằm trong các phương thức nơi logic được viết, dữ liệu được thao tác và tất cả các hành động được thực thi.

  • Instance Variables- Mỗi đối tượng có tập hợp các biến thể hiện duy nhất của nó. Trạng thái của một đối tượng được tạo bởi các giá trị được gán cho các biến thể hiện này.

Cấu trúc chương trình C ++

Chúng ta hãy xem một đoạn mã đơn giản có in dòng chữ Hello World .

#include <iostream>
using namespace std;

// main() is where program execution begins.
int main() {
   cout << "Hello World"; // prints Hello World
   return 0;
}

Chúng ta hãy xem xét các phần khác nhau của chương trình trên -

  • Ngôn ngữ C ++ định nghĩa một số tiêu đề, chứa thông tin cần thiết hoặc hữu ích cho chương trình của bạn. Đối với chương trình này, tiêu đề<iostream> là cần thiết.

  • Dòng using namespace std;yêu cầu trình biên dịch sử dụng không gian tên std. Không gian tên là một bổ sung tương đối gần đây cho C ++.

  • Dòng tiếp theo '// main() is where program execution begins.'là một nhận xét một dòng có sẵn trong C ++. Các chú thích một dòng bắt đầu bằng // và dừng ở cuối dòng.

  • Dòng int main() là chức năng chính bắt đầu thực thi chương trình.

  • Dòng tiếp theo cout << "Hello World"; khiến thông báo "Hello World" được hiển thị trên màn hình.

  • Dòng tiếp theo return 0; chấm dứt hàm main () và khiến nó trả về giá trị 0 cho quá trình gọi.

Biên dịch và thực thi chương trình C ++

Hãy xem cách lưu tệp, biên dịch và chạy chương trình. Vui lòng làm theo các bước dưới đây -

  • Mở một trình soạn thảo văn bản và thêm mã như trên.

  • Lưu tệp dưới dạng: hello.cpp

  • Mở dấu nhắc lệnh và chuyển đến thư mục bạn đã lưu tệp.

  • Nhập 'g ++ hello.cpp' và nhấn enter để biên dịch mã của bạn. Nếu không có lỗi nào trong mã của bạn, dấu nhắc lệnh sẽ đưa bạn đến dòng tiếp theo và sẽ tạo tệp thực thi a.out.

  • Bây giờ, gõ 'a.out' để chạy chương trình của bạn.

  • Bạn sẽ có thể thấy 'Hello World' được in trên cửa sổ.

$ g++ hello.cpp
$ ./a.out
Hello World

Đảm bảo rằng g ++ có trong đường dẫn của bạn và bạn đang chạy nó trong thư mục chứa tệp hello.cpp.

Bạn có thể biên dịch chương trình C / C ++ bằng makefile. Để biết thêm chi tiết, bạn có thể xem 'Hướng dẫn Makefile' của chúng tôi .

Dấu chấm phẩy và khối trong C ++

Trong C ++, dấu chấm phẩy là dấu chấm dứt câu lệnh. Đó là, mỗi câu lệnh riêng lẻ phải được kết thúc bằng dấu chấm phẩy. Nó chỉ ra sự kết thúc của một thực thể logic.

Ví dụ, sau đây là ba câu lệnh khác nhau:

x = y;
y = y + 1;
add(x, y);

Một khối là một tập hợp các câu lệnh được kết nối một cách logic được bao quanh bởi các dấu ngoặc nhọn mở và đóng. Ví dụ -

{
   cout << "Hello World"; // prints Hello World
   return 0;
}

C ++ không nhận ra phần cuối của dòng là dấu chấm hết. Vì lý do này, không quan trọng bạn đặt câu lệnh ở đâu trong một dòng. Ví dụ -

x = y;
y = y + 1;
add(x, y);

giống như

x = y; y = y + 1; add(x, y);

Mã định danh C ++

Mã định danh C ++ là tên được sử dụng để xác định một biến, hàm, lớp, mô-đun hoặc bất kỳ mục nào khác do người dùng xác định. Mã định danh bắt đầu bằng chữ cái A đến Z hoặc từ a đến z hoặc dấu gạch dưới (_) theo sau là không hoặc nhiều chữ cái, dấu gạch dưới và chữ số (0 đến 9).

C ++ không cho phép các ký tự dấu câu như @, $ và% trong các mã định danh. C ++ là một ngôn ngữ lập trình phân biệt chữ hoa chữ thường. Vì vậy,Manpowermanpower là hai định danh khác nhau trong C ++.

Dưới đây là một số ví dụ về số nhận dạng được chấp nhận -

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

Từ khóa C ++

Danh sách sau đây hiển thị các từ dành riêng trong C ++. Những từ dành riêng này không được dùng làm hằng số hoặc biến hoặc bất kỳ tên định danh nào khác.

asm khác Mới điều này
Tự động enum nhà điều hành phi
bool rõ ràng riêng tư thật
phá vỡ xuất khẩu được bảo vệ thử
trường hợp bên ngoài công cộng typedef
nắm lấy sai Đăng ký kiểu chữ
char Phao nổi reinterpret_cast tên loại
lớp học cho trở về liên hiệp
hăng sô bạn bè ngắn chưa ký
const_cast đi đến đã ký sử dụng
tiếp tục nếu kích thước ảo
mặc định nội tuyến tĩnh vô hiệu
xóa bỏ int static_cast bay hơi
làm Dài cấu trúc wchar_t
gấp đôi có thể thay đổi công tắc điện trong khi
dynamic_cast không gian tên bản mẫu  

Đồ thị

Một vài ký tự có cách biểu diễn thay thế, được gọi là chuỗi đoạn. Biểu đồ là một chuỗi ba ký tự đại diện cho một ký tự duy nhất và chuỗi này luôn bắt đầu bằng hai dấu chấm hỏi.

Các đồ thị được mở rộng ở bất cứ nơi nào chúng xuất hiện, bao gồm trong các ký tự chuỗi và ký tự ký tự, trong các chú thích và trong các chỉ thị tiền xử lý.

Sau đây là các trình tự đồ thị được sử dụng thường xuyên nhất -

Trigraph Sự thay thế
?? = #
?? / \
?? ' ^
?? ( [
??) ]
??! |
?? < {
??> }
?? - ~

Tất cả các trình biên dịch đều không hỗ trợ đồ thị và chúng không được khuyến khích sử dụng vì tính chất khó hiểu của chúng.

Khoảng trắng trong C ++

Một dòng chỉ chứa khoảng trắng, có thể kèm theo chú thích, được gọi là dòng trống và trình biên dịch C ++ hoàn toàn bỏ qua nó.

Khoảng trắng là thuật ngữ được sử dụng trong C ++ để mô tả khoảng trống, tab, ký tự dòng mới và nhận xét. Khoảng trắng phân tách một phần của câu lệnh với phần khác và cho phép trình biên dịch xác định vị trí một phần tử trong câu lệnh, chẳng hạn như int, kết thúc và phần tử tiếp theo bắt đầu.

Tuyên bố 1

int age;

Trong câu lệnh trên phải có ít nhất một ký tự khoảng trắng (thường là khoảng trắng) giữa int và age để trình biên dịch có thể phân biệt chúng.

Tuyên bố 2

fruit = apples + oranges;   // Get the total fruit

Trong câu lệnh 2 ở trên, không có ký tự khoảng trắng nào là cần thiết giữa trái cây và =, hoặc giữa = và táo, mặc dù bạn có thể thêm một số ký tự nếu bạn muốn vì mục đích dễ đọc.

Nhận xét chương trình là các câu giải thích mà bạn có thể đưa vào mã C ++. Những nhận xét này giúp ích cho bất kỳ ai đọc mã nguồn. Tất cả các ngôn ngữ lập trình đều cho phép một số dạng nhận xét.

C ++ hỗ trợ bình luận một dòng và nhiều dòng. Tất cả các ký tự có sẵn bên trong bất kỳ nhận xét nào đều bị trình biên dịch C ++ bỏ qua.

Các chú thích C ++ bắt đầu bằng / * và kết thúc bằng * /. Ví dụ -

/* This is a comment */

/* C++ comments can also
   * span multiple lines
*/

Một nhận xét cũng có thể bắt đầu bằng //, kéo dài đến cuối dòng. Ví dụ -

#include <iostream>
using namespace std;

main() {
   cout << "Hello World"; // prints Hello World
   
   return 0;
}

Khi đoạn mã trên được biên dịch, nó sẽ bỏ qua // prints Hello World và tệp thực thi cuối cùng sẽ tạo ra kết quả sau:

Hello World

Trong một bình luận / * và * /, các ký tự // không có ý nghĩa đặc biệt. Trong // nhận xét, / * và * / không có ý nghĩa đặc biệt. Do đó, bạn có thể "lồng" một loại nhận xét vào trong loại khác. Ví dụ -

/* Comment out printing of Hello World:

cout << "Hello World"; // prints Hello World

*/

Trong khi viết chương trình bằng bất kỳ ngôn ngữ nào, bạn cần sử dụng các biến khác nhau để lưu trữ các thông tin khác nhau. Các biến không là gì ngoài các vị trí bộ nhớ dành riêng để lưu trữ các giá trị. Điều này có nghĩa là khi bạn tạo một biến, bạn dành một số không gian trong bộ nhớ.

Bạn có thể muốn lưu trữ thông tin của nhiều kiểu dữ liệu khác nhau như ký tự, ký tự rộng, số nguyên, dấu phẩy động, dấu chấm động kép, boolean, v.v. Dựa trên kiểu dữ liệu của một biến, hệ điều hành phân bổ bộ nhớ và quyết định những gì có thể được lưu trữ trong bộ nhớ dành riêng.

Các loại tích hợp nguyên thủy

C ++ cung cấp cho lập trình viên nhiều loại dữ liệu tích hợp sẵn cũng như kiểu dữ liệu do người dùng xác định. Bảng sau liệt kê bảy kiểu dữ liệu C ++ cơ bản:

Kiểu Từ khóa
Boolean bool
Tính cách char
Số nguyên int
Dấu chấm động Phao nổi
Dấu chấm động kép gấp đôi
Không có giá trị vô hiệu
Nhân vật rộng wchar_t

Một số kiểu cơ bản có thể được sửa đổi bằng cách sử dụng một hoặc nhiều công cụ sửa đổi kiểu này -

  • signed
  • unsigned
  • short
  • long

Bảng sau đây cho thấy loại biến, cần bao nhiêu bộ nhớ để lưu giá trị trong bộ nhớ và giá trị lớn nhất và nhỏ nhất có thể được lưu trong loại biến đó.

Kiểu Chiều rộng bit điển hình Phạm vi điển hình
char 1byte -127 đến 127 hoặc 0 đến 255
ký tự không dấu 1byte 0 đến 255
ký char 1byte -127 đến 127
int 4byte -2147483648 đến 2147483647
int không dấu 4byte 0 đến 4294967295
int đã ký 4byte -2147483648 đến 2147483647
int ngắn 2byte -32768 đến 32767
int ngắn không dấu 2byte 0 đến 65,535
ký ngắn int 2byte -32768 đến 32767
int dài 8byte -2.147.483.648 đến 2.147.483.647
ký dài hạn 8byte giống như long int
int dài unsigned 8byte 0 đến 4,294,967,295
dài dài int 8byte - (2 ^ 63) thành (2 ^ 63) -1
int long long unsigned 8byte 0 đến 18.446.744.073.709.551.615
Phao nổi 4byte
gấp đôi 8byte
dài đôi 12byte
wchar_t 2 hoặc 4 byte 1 ký tự rộng

Kích thước của các biến có thể khác với kích thước được hiển thị trong bảng trên, tùy thuộc vào trình biên dịch và máy tính bạn đang sử dụng.

Sau đây là ví dụ, sẽ tạo ra kích thước chính xác của nhiều loại dữ liệu khác nhau trên máy tính của bạn.

#include <iostream>
using namespace std;

int main() {
   cout << "Size of char : " << sizeof(char) << endl;
   cout << "Size of int : " << sizeof(int) << endl;
   cout << "Size of short int : " << sizeof(short int) << endl;
   cout << "Size of long int : " << sizeof(long int) << endl;
   cout << "Size of float : " << sizeof(float) << endl;
   cout << "Size of double : " << sizeof(double) << endl;
   cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
   
   return 0;
}

Ví dụ này sử dụng endl, sẽ chèn một ký tự dòng mới sau mỗi dòng và toán tử << đang được sử dụng để chuyển nhiều giá trị ra màn hình. Chúng tôi cũng đang sử dụngsizeof() toán tử để nhận kích thước của các kiểu dữ liệu khác nhau.

Khi mã trên được biên dịch và thực thi, nó tạo ra kết quả sau có thể khác nhau giữa các máy:

Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4

Khai báo typedef

Bạn có thể tạo tên mới cho một loại hiện có bằng cách sử dụng typedef. Sau đây là cú pháp đơn giản để xác định một kiểu mới bằng cách sử dụng typedef:

typedef type newname;

Ví dụ, phần sau cho trình biên dịch biết rằng chân là một tên khác của int -

typedef int feet;

Bây giờ, khai báo sau là hoàn toàn hợp pháp và tạo ra một biến số nguyên được gọi là khoảng cách -

feet distance;

Các loại được liệt kê

Kiểu liệt kê khai báo tên kiểu tùy chọn và một tập hợp không hoặc nhiều số nhận dạng có thể được sử dụng làm giá trị của kiểu. Mỗi điều tra viên là một hằng số có kiểu là kiểu liệt kê.

Tạo bảng liệt kê yêu cầu sử dụng từ khóa enum. Dạng tổng quát của kiểu liệt kê là -

enum enum-name { list of names } var-list;

Ở đây, enum-name là tên kiểu của liệt kê. Danh sách tên được phân tách bằng dấu phẩy.

Ví dụ, đoạn mã sau đây xác định một danh sách các màu được gọi là màu và biến c của loại màu. Cuối cùng, c được gán giá trị "blue".

enum color { red, green, blue } c;
c = blue;

Theo mặc định, giá trị của tên đầu tiên là 0, tên thứ hai có giá trị 1 và tên thứ ba có giá trị 2, v.v. Nhưng bạn có thể đặt tên, giá trị cụ thể bằng cách thêm bộ khởi tạo. Ví dụ, trong bảng liệt kê sau,green sẽ có giá trị 5.

enum color { red, green = 5, blue };

Đây, blue sẽ có giá trị là 6 vì mỗi tên sẽ lớn hơn một tên đứng trước nó.

Một biến cung cấp cho chúng ta bộ nhớ được đặt tên mà chương trình của chúng ta có thể thao tác. Mỗi biến trong C ++ có một kiểu cụ thể, xác định kích thước và cách bố trí bộ nhớ của biến; phạm vi giá trị có thể được lưu trữ trong bộ nhớ đó; và tập hợp các thao tác có thể áp dụng cho biến.

Tên của một biến có thể bao gồm các chữ cái, chữ số và ký tự gạch dưới. Nó phải bắt đầu bằng một chữ cái hoặc một dấu gạch dưới. Chữ hoa và chữ thường khác nhau vì C ++ phân biệt chữ hoa chữ thường -

Có các loại biến cơ bản sau trong C ++ như được giải thích trong chương trước:

Sr.No Loại & Mô tả
1

bool

Lưu trữ giá trị đúng hoặc sai.

2

char

Điển hình là một octet đơn (một byte). Đây là một kiểu số nguyên.

3

int

Kích thước tự nhiên nhất của số nguyên cho máy.

4

float

Một giá trị dấu chấm động chính xác duy nhất.

5

double

Giá trị dấu phẩy động có độ chính xác kép.

6

void

Đại diện cho sự vắng mặt của loại.

7

wchar_t

Một kiểu ký tự rộng.

C ++ cũng cho phép xác định nhiều loại biến khác nhau, chúng ta sẽ trình bày trong các chương tiếp theo như Enumeration, Pointer, Array, Reference, Data structures,Classes.

Phần sau sẽ trình bày cách định nghĩa, khai báo và sử dụng các loại biến khác nhau.

Định nghĩa biến trong C ++

Định nghĩa biến cho trình biên dịch biết vị trí và dung lượng lưu trữ cần tạo cho biến. Định nghĩa biến chỉ định một kiểu dữ liệu và chứa danh sách một hoặc nhiều biến của kiểu đó như sau:

type variable_list;

Đây, type phải là kiểu dữ liệu C ++ hợp lệ bao gồm char, w_char, int, float, double, bool hoặc bất kỳ đối tượng nào do người dùng xác định, v.v., và variable_listcó thể bao gồm một hoặc nhiều tên định danh được phân tách bằng dấu phẩy. Một số khai báo hợp lệ được hiển thị ở đây -

int    i, j, k;
char   c, ch;
float  f, salary;
double d;

Dòng int i, j, k;cả khai báo và định nghĩa các biến i, j và k; hướng dẫn trình biên dịch tạo các biến có tên i, j và k kiểu int.

Các biến có thể được khởi tạo (gán giá trị ban đầu) trong khai báo của chúng. Bộ khởi tạo bao gồm một dấu bằng theo sau là một biểu thức hằng số như sau:

type variable_name = value;

Một số ví dụ là -

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'.

Đối với định nghĩa không có bộ khởi tạo: các biến có thời lượng lưu trữ tĩnh được khởi tạo ngầm định với NULL (tất cả các byte đều có giá trị 0); giá trị ban đầu của tất cả các biến khác là không xác định.

Khai báo biến trong C ++

Một khai báo biến cung cấp sự đảm bảo cho trình biên dịch rằng có một biến tồn tại với kiểu và tên đã cho để trình biên dịch tiến hành biên dịch thêm mà không cần chi tiết đầy đủ về biến. Một khai báo biến chỉ có ý nghĩa tại thời điểm biên dịch, trình biên dịch cần định nghĩa biến thực tế tại thời điểm liên kết của chương trình.

Khai báo biến hữu ích khi bạn đang sử dụng nhiều tệp và bạn xác định biến của mình trong một trong các tệp sẽ có sẵn tại thời điểm liên kết chương trình. Bạn sẽ sử dụngexterntừ khóa để khai báo một biến tại bất kỳ vị trí nào. Mặc dù bạn có thể khai báo một biến nhiều lần trong chương trình C ++ của mình, nhưng nó chỉ có thể được định nghĩa một lần trong một tệp, một hàm hoặc một khối mã.

Thí dụ

Hãy thử ví dụ sau trong đó một biến đã được khai báo ở trên cùng, nhưng nó đã được xác định bên trong hàm chính:

#include <iostream>
using namespace std;

// Variable declaration:
extern int a, b;
extern int c;
extern float f;
  
int main () {
   // Variable definition:
   int a, b;
   int c;
   float f;
 
   // actual initialization
   a = 10;
   b = 20;
   c = a + b;
 
   cout << c << endl ;

   f = 70.0/3.0;
   cout << f << endl ;
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

30
23.3333

Khái niệm tương tự áp dụng cho khai báo hàm trong đó bạn cung cấp tên hàm tại thời điểm khai báo và định nghĩa thực tế của nó có thể được cung cấp ở bất kỳ nơi nào khác. Ví dụ -

// function declaration
int func();
int main() {
   // function call
   int i = func();
}

// function definition
int func() {
   return 0;
}

Giá trị và giá trị

Có hai loại biểu thức trong C ++ -

  • lvalue- Các biểu thức tham chiếu đến một vị trí bộ nhớ được gọi là biểu thức "lvalue". Giá trị có thể xuất hiện ở dạng bên trái hoặc bên phải của bài tập.

  • rvalue- Thuật ngữ rvalue đề cập đến một giá trị dữ liệu được lưu trữ tại một số địa chỉ trong bộ nhớ. Giá trị là một biểu thức không thể có giá trị được gán cho nó, có nghĩa là giá trị có thể xuất hiện ở bên phải nhưng không xuất hiện ở bên trái của một phép gán.

Các biến là giá trị và do đó có thể xuất hiện ở phía bên trái của phép gán. Các chữ số là các giá trị và do đó, có thể không được gán và không thể xuất hiện ở phía bên trái. Sau đây là một tuyên bố hợp lệ -

int g = 20;

Nhưng sau đây không phải là một câu lệnh hợp lệ và sẽ tạo ra lỗi thời gian biên dịch -

10 = 20;

Phạm vi là một vùng của chương trình và nói rộng ra có ba vị trí, nơi các biến có thể được khai báo:

  • Bên trong một hàm hoặc một khối được gọi là biến cục bộ,

  • Trong định nghĩa của các tham số chức năng được gọi là tham số hình thức.

  • Bên ngoài tất cả các hàm được gọi là biến toàn cục.

Chúng ta sẽ tìm hiểu hàm là gì và tham số của nó trong các chương tiếp theo. Ở đây, hãy để chúng tôi giải thích biến cục bộ và biến toàn cục là gì.

Biến cục bộ

Các biến được khai báo bên trong một hàm hoặc khối là các biến cục bộ. Chúng chỉ có thể được sử dụng bởi các câu lệnh bên trong hàm hoặc khối mã đó. Các biến cục bộ không được biết đến với các hàm bên ngoài của chúng. Sau đây là ví dụ sử dụng các biến cục bộ:

#include <iostream>
using namespace std;
 
int main () {
   // Local variable declaration:
   int a, b;
   int c;
 
   // actual initialization
   a = 10;
   b = 20;
   c = a + b;
 
   cout << c;
 
   return 0;
}

Biến toàn cục

Các biến toàn cục được định nghĩa bên ngoài tất cả các hàm, thường nằm trên đầu chương trình. Các biến toàn cục sẽ giữ giá trị của chúng trong suốt thời gian tồn tại của chương trình của bạn.

Một biến toàn cục có thể được truy cập bởi bất kỳ hàm nào. Có nghĩa là, một biến toàn cục có sẵn để sử dụng trong toàn bộ chương trình của bạn sau khi khai báo. Sau đây là ví dụ sử dụng các biến cục bộ và toàn cục:

#include <iostream>
using namespace std;
 
// Global variable declaration:
int g;
 
int main () {
   // Local variable declaration:
   int a, b;
 
   // actual initialization
   a = 10;
   b = 20;
   g = a + b;
  
   cout << g;
 
   return 0;
}

Một chương trình có thể có cùng tên cho các biến cục bộ và toàn cục nhưng giá trị của biến cục bộ bên trong một hàm sẽ được ưu tiên. Ví dụ -

#include <iostream>
using namespace std;
 
// Global variable declaration:
int g = 20;
 
int main () {
   // Local variable declaration:
   int g = 10;
 
   cout << g;
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

10

Khởi tạo các biến cục bộ và toàn cục

Khi một biến cục bộ được xác định, nó không được khởi tạo bởi hệ thống, bạn phải tự khởi tạo nó. Các biến toàn cục được khởi tạo tự động bởi hệ thống khi bạn định nghĩa chúng như sau:

Loại dữ liệu Bộ khởi tạo
int 0
char '\ 0'
Phao nổi 0
gấp đôi 0
con trỏ VÔ GIÁ TRỊ

Thực hành lập trình tốt là khởi tạo các biến đúng cách, nếu không, đôi khi chương trình sẽ tạo ra kết quả không mong muốn.

Hằng số đề cập đến các giá trị cố định mà chương trình không thể thay đổi và chúng được gọi là literals.

Hằng số có thể thuộc bất kỳ kiểu dữ liệu cơ bản nào và có thể được chia thành Số nguyên, Số dấu phẩy động, Ký tự, Chuỗi và Giá trị Boolean.

Một lần nữa, các hằng được xử lý giống như các biến thông thường ngoại trừ giá trị của chúng không thể được sửa đổi sau khi định nghĩa.

Chữ số nguyên

Một chữ số nguyên có thể là một hằng số thập phân, bát phân hoặc thập lục phân. Tiền tố chỉ định cơ số hoặc cơ số: 0x hoặc 0X cho hệ thập lục phân, 0 cho hệ bát phân và không có gì cho thập phân.

Một chữ số nguyên cũng có thể có một hậu tố là sự kết hợp của U và L, tương ứng là không dấu và dài. Hậu tố có thể là chữ hoa hoặc chữ thường và có thể theo bất kỳ thứ tự nào.

Dưới đây là một số ví dụ về các ký tự số nguyên -

212         // Legal
215u        // Legal
0xFeeL      // Legal
078         // Illegal: 8 is not an octal digit
032UU       // Illegal: cannot repeat a suffix

Sau đây là các ví dụ khác về các loại ký tự Số nguyên khác nhau -

85         // decimal
0213       // octal
0x4b       // hexadecimal
30         // int
30u        // unsigned int
30l        // long
30ul       // unsigned long

Chữ nổi dấu chấm động

Một ký tự dấu phẩy động có một phần nguyên, một dấu thập phân, một phần thập phân và một phần mũ. Bạn có thể biểu diễn các ký tự dấu phẩy động ở dạng thập phân hoặc dạng hàm mũ.

Trong khi biểu diễn bằng cách sử dụng dạng thập phân, bạn phải bao gồm dấu thập phân, số mũ hoặc cả hai và trong khi biểu diễn bằng cách sử dụng dạng mũ, bạn phải bao gồm phần nguyên, phần thập phân hoặc cả hai. Số mũ có dấu được giới thiệu bởi e hoặc E.

Dưới đây là một số ví dụ về các ký tự dấu phẩy động -

3.14159       // Legal
314159E-5L    // Legal
510E          // Illegal: incomplete exponent
210f          // Illegal: no decimal or exponent
.e55          // Illegal: missing integer or fraction

Boolean Literals

Có hai ký tự Boolean và chúng là một phần của các từ khóa C ++ chuẩn -

  • Một giá trị của true đại diện cho sự thật.

  • Một giá trị của false đại diện cho sai.

Bạn không nên coi giá trị của true bằng 1 và giá trị của false bằng 0.

Ký tự chữ

Các ký tự ký tự được đặt trong dấu ngoặc kép. Nếu ký tự bắt đầu bằng L (chỉ viết hoa), thì đó là một ký tự rộng (ví dụ: L'x ') và phải được lưu trữ trongwchar_tloại biến. Nếu không, nó là một ký tự hẹp (ví dụ: 'x') và có thể được lưu trữ trong một biến đơn giản củachar kiểu.

Một chữ ký tự có thể là một ký tự thuần túy (ví dụ: 'x'), một chuỗi thoát (ví dụ: '\ t') hoặc một ký tự phổ quát (ví dụ: '\ u02C0').

Có một số ký tự nhất định trong C ++ khi chúng đứng trước dấu gạch chéo ngược, chúng sẽ có ý nghĩa đặc biệt và chúng được sử dụng để biểu diễn như dòng mới (\ n) hoặc tab (\ t). Tại đây, bạn có danh sách một số mã trình tự thoát như vậy -

Trình tự thoát Ý nghĩa
\\ \ tính cách
\ ' ' tính cách
\ " " tính cách
\? ? tính cách
\ a Cảnh báo hoặc chuông
\ b Backspace
\ f Thức ăn dạng
\ n Dòng mới
\ r Vận chuyển trở lại
\ t Tab ngang
\ v Tab dọc
\ ooo Số bát phân từ một đến ba chữ số
\ xhh. . . Số thập lục phân gồm một hoặc nhiều chữ số

Sau đây là ví dụ để hiển thị một vài ký tự thoát -

#include <iostream>
using namespace std;

int main() {
   cout << "Hello\tWorld\n\n";
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Hello   World

Chuỗi chữ

Các ký tự chuỗi được đặt trong dấu ngoặc kép. Một chuỗi chứa các ký tự tương tự như các ký tự: ký tự thuần túy, chuỗi thoát và ký tự phổ quát.

Bạn có thể ngắt một dòng dài thành nhiều dòng bằng cách sử dụng các ký tự chuỗi và phân tách chúng bằng cách sử dụng khoảng trắng.

Dưới đây là một số ví dụ về chuỗi ký tự. Tất cả ba hình thức là các chuỗi giống hệt nhau.

"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

Định nghĩa Hằng số

Có hai cách đơn giản trong C ++ để định nghĩa hằng số:

  • Sử dụng #define bộ tiền xử lý.

  • Sử dụng const từ khóa.

#Define Preprocessor

Sau đây là biểu mẫu sử dụng bộ tiền xử lý #define để xác định một hằng số -

#define identifier value

Ví dụ sau giải thích nó một cách chi tiết -

#include <iostream>
using namespace std;

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

int main() {
   int area;  
   
   area = LENGTH * WIDTH;
   cout << area;
   cout << NEWLINE;
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

50

Từ khoá const

Bạn có thể dùng const tiền tố để khai báo các hằng với một kiểu cụ thể như sau:

const type variable = value;

Ví dụ sau giải thích nó một cách chi tiết -

#include <iostream>
using namespace std;

int main() {
   const int  LENGTH = 10;
   const int  WIDTH  = 5;
   const char NEWLINE = '\n';
   int area;  
   
   area = LENGTH * WIDTH;
   cout << area;
   cout << NEWLINE;
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

50

Lưu ý rằng đó là một thực hành lập trình tốt để xác định hằng số trong CHỮ HOA.

C ++ cho phép char, int, doublecác kiểu dữ liệu có các bổ ngữ đứng trước chúng. Một bổ ngữ được sử dụng để thay đổi ý nghĩa của loại cơ sở để nó phù hợp chính xác hơn với nhu cầu của các tình huống khác nhau.

Các công cụ sửa đổi kiểu dữ liệu được liệt kê ở đây -

  • signed
  • unsigned
  • long
  • short

Các bổ ngữ signed, unsigned, long,shortcó thể được áp dụng cho các kiểu cơ sở số nguyên. Ngoài ra,signedunsigned có thể được áp dụng cho ký tự, và long có thể được áp dụng để tăng gấp đôi.

Các bổ ngữ signedunsigned cũng có thể được sử dụng làm tiền tố cho long hoặc là shortbổ ngữ. Ví dụ,unsigned long int.

C ++ cho phép một ký hiệu viết tắt để khai báo unsigned, short, hoặc là longsố nguyên. Bạn chỉ có thể sử dụng từunsigned, short, hoặc là long, không có int. Nó tự động ngụ ýint. Ví dụ, hai câu lệnh sau đều khai báo các biến số nguyên không dấu.

unsigned x;
unsigned int y;

Để hiểu sự khác biệt giữa cách mà các công cụ sửa đổi số nguyên có dấu và không dấu được diễn giải bởi C ++, bạn nên chạy chương trình ngắn sau:

#include <iostream>
using namespace std;
 
/* This program shows the difference between
   * signed and unsigned integers.
*/
int main() {
   short int i;           // a signed short integer
   short unsigned int j;  // an unsigned short integer

   j = 50000;

   i = j;
   cout << i << " " << j;

   return 0;
}

Khi chương trình này được chạy, sau đây là kết quả:

-15536 50000

Kết quả trên là do mẫu bit đại diện cho 50.000 dưới dạng số nguyên không dấu ngắn được hiểu là -15,536 ngắn gọn.

Nhập Qualifier trong C ++

Các bộ định loại cung cấp thông tin bổ sung về các biến mà chúng đứng trước.

Sr.No Vòng loại và ý nghĩa
1

const

Đối tượng của loại const không thể bị thay đổi bởi chương trình của bạn trong quá trình thực thi.

2

volatile

Bổ ngữ volatile cho trình biên dịch biết rằng giá trị của một biến có thể bị thay đổi theo những cách không được chương trình chỉ định rõ ràng.

3

restrict

Một con trỏ đủ điều kiện bởi restrictban đầu là phương tiện duy nhất mà đối tượng mà nó trỏ tới có thể được truy cập. Chỉ C99 thêm một bộ định tính loại mới được gọi là hạn chế.

Một lớp lưu trữ xác định phạm vi (khả năng hiển thị) và thời gian tồn tại của các biến và / hoặc các hàm trong Chương trình C ++. Các chỉ định này đứng trước loại mà chúng sửa đổi. Có các lớp lưu trữ sau, có thể được sử dụng trong Chương trình C ++

  • auto
  • register
  • static
  • extern
  • mutable

Lớp lưu trữ tự động

Các auto lớp lưu trữ là lớp lưu trữ mặc định cho tất cả các biến cục bộ.

{
   int mount;
   auto int month;
}

Ví dụ trên định nghĩa hai biến có cùng lớp lưu trữ, auto chỉ có thể được sử dụng trong các hàm, tức là các biến cục bộ.

Lớp lưu trữ đăng ký

Các registerlớp lưu trữ được sử dụng để xác định các biến cục bộ cần được lưu trữ trong một thanh ghi thay vì RAM. Điều này có nghĩa là biến có kích thước tối đa bằng kích thước thanh ghi (thường là một từ) và không thể áp dụng toán tử '&' một bậc cho nó (vì nó không có vị trí bộ nhớ).

{
   register int  miles;
}

Thanh ghi chỉ nên được sử dụng cho các biến yêu cầu truy cập nhanh như bộ đếm. Cũng cần lưu ý rằng việc xác định 'register' không có nghĩa là biến sẽ được lưu trữ trong một thanh ghi. Nó có nghĩa là nó CÓ THỂ được lưu trữ trong một thanh ghi tùy thuộc vào phần cứng và các hạn chế triển khai.

Lớp lưu trữ tĩnh

Các staticlớp lưu trữ hướng dẫn trình biên dịch giữ một biến cục bộ tồn tại trong thời gian tồn tại của chương trình thay vì tạo và hủy nó mỗi khi nó xuất hiện và đi ra khỏi phạm vi. Do đó, việc làm cho các biến cục bộ trở nên tĩnh cho phép chúng duy trì các giá trị của chúng giữa các lần gọi hàm.

Công cụ sửa đổi tĩnh cũng có thể được áp dụng cho các biến toàn cục. Khi điều này được thực hiện, nó khiến phạm vi của biến đó bị giới hạn trong tệp mà nó được khai báo.

Trong C ++, khi static được sử dụng trên một thành viên dữ liệu của lớp, nó khiến chỉ một bản sao của thành viên đó được chia sẻ bởi tất cả các đối tượng của lớp nó.

#include <iostream>
 
// Function declaration
void func(void);
 
static int count = 10; /* Global variable */
 
main() {
   while(count--) {
      func();
   }
   
   return 0;
}

// Function definition
void func( void ) {
   static int i = 5; // local static variable
   i++;
   std::cout << "i is " << i ;
   std::cout << " and count is " << count << std::endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

i is 6 and count is 9
i is 7 and count is 8
i is 8 and count is 7
i is 9 and count is 6
i is 10 and count is 5
i is 11 and count is 4
i is 12 and count is 3
i is 13 and count is 2
i is 14 and count is 1
i is 15 and count is 0

Lớp lưu trữ bên ngoài

Các externlớp lưu trữ được sử dụng để cung cấp một tham chiếu của một biến toàn cục hiển thị cho TẤT CẢ các tệp chương trình. Khi bạn sử dụng 'extern', biến không thể được khởi tạo vì tất cả những gì nó làm là trỏ tên biến vào vị trí lưu trữ đã được xác định trước đó.

Khi bạn có nhiều tệp và bạn xác định một biến hoặc hàm toàn cục, biến hoặc hàm này cũng sẽ được sử dụng trong các tệp khác, thì extern sẽ được sử dụng trong tệp khác để cung cấp tham chiếu của biến hoặc hàm đã xác định. Chỉ để hiểu extern được sử dụng để khai báo một biến hoặc hàm toàn cục trong một tệp khác.

Công cụ sửa đổi extern thường được sử dụng nhất khi có hai hoặc nhiều tệp chia sẻ cùng các biến hoặc hàm toàn cục như được giải thích bên dưới.

Tệp đầu tiên: main.cpp

#include <iostream>
int count ;
extern void write_extern();
 
main() {
   count = 5;
   write_extern();
}

Tệp thứ hai: support.cpp

#include <iostream>

extern int count;

void write_extern(void) {
   std::cout << "Count is " << count << std::endl;
}

Ở đây, từ khóa extern đang được sử dụng để khai báo số lượng trong một tệp khác. Bây giờ biên dịch hai tệp này như sau:

$g++ main.cpp support.cpp -o write

Điều này sẽ tạo ra write chương trình thực thi, cố gắng thực thi write và kiểm tra kết quả như sau:

$./write
5

Lớp lưu trữ có thể thay đổi

Các mutablespecifier chỉ áp dụng cho các đối tượng lớp, sẽ được thảo luận sau trong hướng dẫn này. Nó cho phép một thành viên của một đối tượng ghi đè hàm thành viên const. Nghĩa là, một thành viên có thể thay đổi có thể được sửa đổi bởi một hàm thành viên const.

Một toán tử là một ký hiệu yêu cầu trình biên dịch thực hiện các thao tác toán học hoặc logic cụ thể. C ++ có nhiều toán tử cài sẵn và cung cấp các loại toán tử sau:

  • Toán tử số học
  • Toán tử quan hệ
  • Toán tử logic
  • Toán tử Bitwise
  • Người điều hành nhiệm vụ
  • Nhà điều hành khác

Chương này sẽ lần lượt xem xét các toán tử số học, quan hệ, logic, bitwise, phép gán và các toán tử khác.

Toán tử số học

Có các toán tử số học sau được ngôn ngữ C ++ hỗ trợ:

Giả sử biến A giữ 10 và biến B giữ 20, thì -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
+ Thêm hai toán hạng A + B sẽ cho 30
- Trừ toán hạng thứ hai với toán hạng đầu tiên A - B sẽ cho -10
* Nhân cả hai toán hạng A * B sẽ cho 200
/ Chia tử số cho tử số B / A sẽ cho 2
% Toán tử mô đun và phần còn lại của sau một phép chia số nguyên B% A sẽ cho 0
++ Toán tử tăng dần , tăng giá trị số nguyên lên một A ++ sẽ cho 11
- Toán tử giảm dần, giảm giá trị số nguyên đi một A-- sẽ cho 9

Toán tử quan hệ

Có các toán tử quan hệ sau được ngôn ngữ C ++ hỗ trợ

Giả sử biến A giữ 10 và biến B giữ 20, thì -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
== Kiểm tra xem giá trị của hai toán hạng có bằng nhau hay không, nếu có thì điều kiện trở thành true. (A == B) không đúng.
! = Kiểm tra xem giá trị của hai toán hạng có bằng nhau hay không, nếu các giá trị không bằng nhau thì điều kiện trở thành true. (A! = B) là đúng.
> Kiểm tra xem giá trị của toán hạng bên trái có lớn hơn giá trị của toán hạng bên phải hay không, nếu có thì điều kiện trở thành true. (A> B) là không đúng.
< Kiểm tra xem giá trị của toán hạng bên trái có nhỏ hơn giá trị của toán hạng bên phải hay không, nếu có thì điều kiện trở thành true. (A <B) là đúng.
> = Kiểm tra xem giá trị của toán hạng bên trái có lớn hơn hoặc bằng giá trị của toán hạng bên phải hay không, nếu có thì điều kiện trở thành true. (A> = B) là không đúng.
<= Kiểm tra xem giá trị của toán hạng bên trái có nhỏ hơn hoặc bằng giá trị của toán hạng bên phải hay không, nếu có thì điều kiện trở thành true. (A <= B) là đúng.

Toán tử logic

Có các toán tử logic sau được ngôn ngữ C ++ hỗ trợ.

Giả sử biến A giữ 1 và biến B giữ 0, sau đó -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
&& Được gọi là toán tử logic AND. Nếu cả hai toán hạng đều khác 0, thì điều kiện trở thành true. (A && B) là sai.
|| Được gọi là Toán tử logic HOẶC. Nếu bất kỳ toán hạng nào trong hai toán hạng khác 0, thì điều kiện trở thành true. (A || B) là đúng.
! Được gọi là Toán tử logic NOT. Sử dụng để đảo ngược trạng thái logic của toán hạng của nó. Nếu một điều kiện là đúng, thì toán tử logic NOT sẽ sai. ! (A && B) là đúng.

Toán tử Bitwise

Toán tử bitwise hoạt động trên các bit và thực hiện thao tác từng bit. Bảng sự thật cho &, |, và ^ như sau:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Giả sử nếu A = 60; và B = 13; bây giờ ở định dạng nhị phân, chúng sẽ như sau:

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

Các toán tử Bitwise được hỗ trợ bởi ngôn ngữ C ++ được liệt kê trong bảng sau. Giả sử biến A giữ 60 và biến B giữ 13, thì -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
& Toán tử AND nhị phân sao chép một bit vào kết quả nếu nó tồn tại trong cả hai toán hạng. (A & B) sẽ cho kết quả 12 là 0000 1100
| Toán tử OR nhị phân sao chép một bit nếu nó tồn tại trong một trong hai toán hạng. (A | B) sẽ cho 61 là 0011 1101
^ Toán tử XOR nhị phân sao chép bit nếu nó được đặt trong một toán hạng nhưng không phải cả hai. (A ^ B) sẽ cho 49 là 0011 0001
~ Toán tử bổ sung số nhị phân là một ngôi và có tác dụng 'lật' các bit. (~ A) sẽ cho -61 là 1100 0011 ở dạng phần bù của 2 do một số nhị phân có dấu.
<< Toán tử dịch chuyển trái nhị phân. Giá trị toán hạng bên trái được di chuyển sang trái bằng số bit được chỉ định bởi toán hạng bên phải. A << 2 sẽ cho 240 là 1111 0000
>> Toán tử Shift phải nhị phân. Giá trị của toán hạng bên trái được di chuyển sang phải bằng số bit được chỉ định bởi toán hạng bên phải. A >> 2 sẽ cho 15 là 0000 1111

Người điều hành nhiệm vụ

Có các toán tử gán sau được ngôn ngữ C ++ hỗ trợ:

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
= Toán tử gán đơn giản, Gán giá trị từ toán hạng bên phải sang toán hạng bên trái. C = A + B sẽ gán giá trị của A + B vào C
+ = Thêm toán tử gán AND, Nó thêm toán hạng bên phải vào toán hạng bên trái và gán kết quả cho toán hạng bên trái. C + = A tương đương với C = C + A
- = Trừ toán tử gán AND, Nó trừ toán hạng bên phải khỏi toán hạng bên trái và gán kết quả cho toán hạng bên trái. C - = A tương đương với C = C - A
* = Nhân toán tử gán AND, Nó nhân toán hạng bên phải với toán hạng bên trái và gán kết quả cho toán hạng bên trái. C * = A tương đương với C = C * A
/ = Toán tử gán AND, Nó chia toán hạng bên trái với toán hạng bên phải và gán kết quả cho toán hạng bên trái. C / = A tương đương với C = C / A
% = Toán tử gán mô-đun AND, Cần mô-đun sử dụng hai toán hạng và gán kết quả cho toán hạng bên trái. C% = A tương đương với C = C% A
<< = Dịch chuyển trái toán tử gán AND. C << = 2 giống với C = C << 2
>> = Toán tử gán dịch chuyển phải AND. C >> = 2 giống với C = C >> 2
& = Toán tử gán bitwise AND. C & = 2 giống C = C & 2
^ = Toán tử OR và gán độc quyền bitwise. C ^ = 2 giống với C = C ^ 2
| = Bitwise bao gồm OR và toán tử gán. C | = 2 tương tự như C = C | 2

Nhà điều hành khác

Bảng sau liệt kê một số toán tử khác mà C ++ hỗ trợ.

Sr.No Nhà điều hành & Mô tả
1

sizeof

toán tử sizeof trả về kích thước của một biến. Ví dụ: sizeof (a), trong đó 'a' là số nguyên và sẽ trả về 4.

2

Condition ? X : Y

Toán tử điều kiện (?) . Nếu Điều kiện là đúng thì nó trả về giá trị của X, ngược lại trả về giá trị của Y.

3

,

Toán tử dấu phẩy gây ra một chuỗi hoạt động được thực hiện. Giá trị của toàn bộ biểu thức dấu phẩy là giá trị của biểu thức cuối cùng của danh sách được phân tách bằng dấu phẩy.

4

. (dot) and -> (arrow)

Các toán tử thành viên được sử dụng để tham chiếu các thành viên riêng lẻ của các lớp, cấu trúc và liên hiệp.

5

Cast

Các toán tử truyền chuyển đổi kiểu dữ liệu này sang kiểu dữ liệu khác. Ví dụ, int (2.2000) sẽ trả về 2.

6

&

Toán tử con trỏ & trả về địa chỉ của một biến. Ví dụ & a; sẽ cung cấp địa chỉ thực của biến.

7

*

Toán tử con trỏ * là con trỏ tới một biến. Ví dụ * var; sẽ trỏ đến một biến var.

Ưu tiên toán tử trong C ++

Mức độ ưu tiên của toán tử xác định nhóm các từ trong một biểu thức. Điều này ảnh hưởng đến cách một biểu thức được đánh giá. Các toán tử nhất định có quyền ưu tiên cao hơn những toán tử khác; ví dụ, toán tử nhân có mức độ ưu tiên cao hơn toán tử cộng -

Ví dụ x = 7 + 3 * 2; ở đây, x được gán 13, không phải 20 vì toán tử * có mức độ ưu tiên cao hơn +, vì vậy đầu tiên nó được nhân với 3 * 2 và sau đó cộng thành 7.

Ở đây, các toán tử có mức độ ưu tiên cao nhất xuất hiện ở đầu bảng, những toán tử có mức độ ưu tiên thấp nhất xuất hiện ở cuối bảng. Trong một biểu thức, các toán tử có mức độ ưu tiên cao hơn sẽ được đánh giá đầu tiên.

Hiển thị các ví dụ

thể loại  Nhà điều hành  Sự liên kết 
Postfix  () [] ->. ++ - -   Trái sang phải 
Một ngôi  + -! ~ ++ - - (type) * & sizeof  Phải sang trái 
Phép nhân   * /%  Trái sang phải 
Phụ gia   + -  Trái sang phải 
Shift   << >>  Trái sang phải 
Quan hệ   <<=>> =  Trái sang phải 
Bình đẳng   ==! =  Trái sang phải 
Bitwise VÀ  Trái sang phải 
Bitwise XOR  Trái sang phải 
Bitwise HOẶC  Trái sang phải 
Logic AND  &&  Trái sang phải 
Logic HOẶC  ||  Trái sang phải 
Có điều kiện  ?:  Phải sang trái 
Chuyển nhượng  = + = - = * = / =% = >> = << = & = ^ = | =  Phải sang trái 
Dấu phẩy  Trái sang phải 

Có thể có một tình huống, khi bạn cần thực thi một khối mã nhiều lần. Nói chung, các câu lệnh được thực hiện tuần tự: Câu lệnh đầu tiên trong một hàm được thực hiện đầu tiên, tiếp theo là câu lệnh thứ hai, v.v.

Các ngôn ngữ lập trình cung cấp các cấu trúc điều khiển khác nhau cho phép các đường dẫn thực thi phức tạp hơn.

Một câu lệnh lặp cho phép chúng ta thực hiện một câu lệnh hoặc một nhóm câu lệnh nhiều lần và sau đây là tổng quát từ câu lệnh lặp trong hầu hết các ngôn ngữ lập trình:

Ngôn ngữ lập trình C ++ cung cấp các loại vòng lặp sau để xử lý các yêu cầu về lặp.

Sr.No Loại vòng lặp & Mô tả
1 trong khi lặp lại

Lặp lại một câu lệnh hoặc một nhóm câu lệnh trong khi một điều kiện đã cho là đúng. Nó kiểm tra điều kiện trước khi thực thi phần thân của vòng lặp.

2 vòng lặp for

Thực thi một chuỗi các câu lệnh nhiều lần và viết tắt mã quản lý biến vòng lặp.

3 vòng lặp do ... while

Giống như một câu lệnh 'while', ngoại trừ việc nó kiểm tra điều kiện ở cuối thân vòng lặp.

4 vòng lồng nhau

Bạn có thể sử dụng một hoặc nhiều vòng lặp bên trong bất kỳ vòng lặp 'while', 'for' hoặc 'do..ared' nào khác.

Tuyên bố kiểm soát vòng lặp

Các câu lệnh điều khiển vòng lặp thay đổi việc thực thi từ trình tự bình thường của nó. Khi việc thực thi rời khỏi một phạm vi, tất cả các đối tượng tự động được tạo trong phạm vi đó sẽ bị phá hủy.

C ++ hỗ trợ các câu lệnh điều khiển sau.

Sr.No Tuyên bố & Mô tả Kiểm soát
1 tuyên bố ngắt

Chấm dứt loop hoặc là switch và chuyển việc thực thi đến câu lệnh ngay sau vòng lặp hoặc chuyển đổi.

2 tiếp tục tuyên bố

Làm cho vòng lặp bỏ qua phần còn lại của phần thân và ngay lập tức kiểm tra lại tình trạng của nó trước khi nhắc lại.

3 tuyên bố goto

Chuyển quyền điều khiển sang câu lệnh được gắn nhãn. Mặc dù không nên sử dụng câu lệnh goto trong chương trình của bạn.

Vòng lặp vô hạn

Một vòng lặp trở thành vòng lặp vô hạn nếu một điều kiện không bao giờ trở thành sai. Cácforvòng lặp thường được sử dụng cho mục đích này. Vì không có biểu thức nào trong ba biểu thức tạo thành vòng lặp 'for' được yêu cầu, bạn có thể tạo một vòng lặp vô tận bằng cách để trống biểu thức điều kiện.

#include <iostream>
using namespace std;
 
int main () {
   for( ; ; ) {
      printf("This loop will run forever.\n");
   }

   return 0;
}

Khi biểu thức điều kiện vắng mặt, nó được giả định là đúng. Bạn có thể có một biểu thức khởi tạo và tăng dần, nhưng các lập trình viên C ++ thường sử dụng cấu trúc 'for (;;)' để biểu thị một vòng lặp vô hạn.

NOTE - Bạn có thể kết thúc một vòng lặp vô hạn bằng cách nhấn các phím Ctrl + C.

Cấu trúc ra quyết định yêu cầu người lập trình chỉ định một hoặc nhiều điều kiện để được đánh giá hoặc kiểm tra bởi chương trình, cùng với một câu lệnh hoặc các câu lệnh sẽ được thực thi nếu điều kiện đó được xác định là đúng và tùy chọn, các câu lệnh khác được thực thi nếu điều kiện được xác định là sai.

Sau đây là dạng chung của cấu trúc ra quyết định điển hình được tìm thấy trong hầu hết các ngôn ngữ lập trình:

Ngôn ngữ lập trình C ++ cung cấp các loại câu lệnh ra quyết định sau.

Sr.No Tuyên bố & Mô tả
1 câu lệnh if

Câu lệnh 'if' bao gồm một biểu thức boolean theo sau là một hoặc nhiều câu lệnh.

2 câu lệnh if ... else

Câu lệnh 'if' có thể được theo sau bởi một câu lệnh 'else' tùy chọn, thực thi khi biểu thức boolean sai.

3 chuyển đổi tuyên bố

Câu lệnh 'switch' cho phép một biến được kiểm tra tính bình đẳng với danh sách các giá trị.

4 câu lệnh if lồng nhau

Bạn có thể sử dụng một câu lệnh 'if' hoặc 'else if' bên trong (các) câu lệnh 'if' hoặc 'else if' khác.

5 các câu lệnh chuyển đổi lồng nhau

Bạn có thể sử dụng một câu lệnh 'switch' bên trong (các) câu lệnh 'switch' khác.

Các ? : Nhà điều hành

Chúng tôi đã đề cập đến toán tử có điều kiện “? : ” Trong chương trước có thể được sử dụng để thay thếif...elsecác câu lệnh. Nó có dạng chung sau:

Exp1 ? Exp2 : Exp3;

Exp1, Exp2 và Exp3 là các biểu thức. Chú ý công dụng và vị trí của dấu hai chấm.

Giá trị của dấu '?' biểu thức được xác định như thế này: Exp1 được đánh giá. Nếu nó đúng, thì Exp2 được đánh giá và trở thành giá trị của toàn bộ '?' biểu hiện. Nếu Exp1 là false, thì Exp3 được đánh giá và giá trị của nó trở thành giá trị của biểu thức.

Hàm là một nhóm các câu lệnh cùng thực hiện một tác vụ. Mỗi chương trình C ++ đều có ít nhất một hàm, đó làmain(), và tất cả các chương trình tầm thường nhất có thể xác định các chức năng bổ sung.

Bạn có thể chia mã của mình thành các chức năng riêng biệt. Cách bạn phân chia mã của mình giữa các chức năng khác nhau là tùy thuộc vào bạn, nhưng về mặt logic, việc phân chia thường là sao cho mỗi chức năng thực hiện một nhiệm vụ cụ thể.

Một chức năng declarationcho trình biên dịch biết về tên, kiểu trả về và các tham số của hàm. Một chức năngdefinition cung cấp phần thân thực tế của hàm.

Thư viện chuẩn C ++ cung cấp nhiều hàm tích hợp sẵn mà chương trình của bạn có thể gọi. Ví dụ, hàmstrcat() để nối hai chuỗi, hàm memcpy() để sao chép một vị trí bộ nhớ sang một vị trí khác và nhiều chức năng khác.

Một hàm được biết đến với nhiều tên khác nhau như một phương thức hoặc một quy trình con hoặc một thủ tục, v.v.

Xác định một chức năng

Dạng tổng quát của định nghĩa hàm C ++ như sau:

return_type function_name( parameter list ) {
   body of the function
}

Định nghĩa hàm trong C ++ bao gồm tiêu đề hàm và thân hàm. Đây là tất cả các phần của một hàm -

  • Return Type- Một hàm có thể trả về một giá trị. Cácreturn_typelà kiểu dữ liệu của giá trị mà hàm trả về. Một số hàm thực hiện các hoạt động mong muốn mà không trả về giá trị. Trong trường hợp này, return_type là từ khóavoid.

  • Function Name- Đây là tên thực của hàm. Tên hàm và danh sách tham số cùng nhau tạo thành chữ ký hàm.

  • Parameters- Một tham số giống như một trình giữ chỗ. Khi một hàm được gọi, bạn truyền một giá trị cho tham số. Giá trị này được gọi là tham số hoặc đối số thực tế. Danh sách tham số đề cập đến kiểu, thứ tự và số lượng các tham số của một hàm. Các thông số là tùy chọn; nghĩa là, một hàm có thể không chứa tham số.

  • Function Body - Phần thân hàm chứa tập hợp các câu lệnh xác định chức năng thực hiện.

Thí dụ

Sau đây là mã nguồn cho một hàm được gọi là max(). Hàm này nhận hai tham số num1 và num2 và trả về giá trị lớn nhất trong cả hai:

// function returning the max between two numbers
 
int max(int num1, int num2) {
   // local variable declaration
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Khai báo hàm

Một chức năng declarationcho trình biên dịch biết về tên hàm và cách gọi hàm. Phần thân thực của hàm có thể được định nghĩa riêng biệt.

Một khai báo hàm có các phần sau:

return_type function_name( parameter list );

Đối với hàm max () được định nghĩa ở trên, sau đây là khai báo hàm:

int max(int num1, int num2);

Tên tham số không quan trọng trong khai báo hàm chỉ cần kiểu của chúng, vì vậy sau đây cũng là khai báo hợp lệ:

int max(int, int);

Khai báo hàm là bắt buộc khi bạn xác định một hàm trong một tệp nguồn và bạn gọi hàm đó trong một tệp khác. Trong trường hợp này, bạn nên khai báo hàm ở đầu tệp gọi hàm.

Gọi một hàm

Trong khi tạo một hàm C ++, bạn đưa ra định nghĩa về những gì hàm phải làm. Để sử dụng một hàm, bạn sẽ phải gọi hoặc gọi hàm đó.

Khi một chương trình gọi một chức năng, điều khiển chương trình sẽ được chuyển sang chức năng được gọi. Một hàm được gọi thực hiện tác vụ được xác định và khi câu lệnh trả về của nó được thực thi hoặc khi đạt đến dấu ngoặc nhọn kết thúc hàm, nó sẽ trả lại điều khiển chương trình trở lại chương trình chính.

Để gọi một hàm, bạn chỉ cần chuyển các tham số bắt buộc cùng với tên hàm và nếu hàm trả về một giá trị, thì bạn có thể lưu trữ giá trị trả về. Ví dụ -

#include <iostream>
using namespace std;
 
// function declaration
int max(int num1, int num2);
 
int main () {
   // local variable declaration:
   int a = 100;
   int b = 200;
   int ret;
 
   // calling a function to get max value.
   ret = max(a, b);
   cout << "Max value is : " << ret << endl;
 
   return 0;
}
 
// function returning the max between two numbers
int max(int num1, int num2) {
   // local variable declaration
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Tôi đã giữ hàm max () cùng với hàm main () và biên dịch mã nguồn. Trong khi chạy tệp thực thi cuối cùng, nó sẽ tạo ra kết quả sau:

Max value is : 200

Đối số hàm

Nếu một hàm sử dụng các đối số, nó phải khai báo các biến chấp nhận giá trị của các đối số. Các biến này được gọi làformal parameters của hàm.

Các tham số chính thức hoạt động giống như các biến cục bộ khác bên trong hàm và được tạo khi nhập vào hàm và bị hủy khi thoát.

Trong khi gọi một hàm, có hai cách mà các đối số có thể được truyền cho một hàm:

Sr.No Loại & Mô tả Cuộc gọi
1 Gọi theo giá trị

Phương thức này sao chép giá trị thực của một đối số vào tham số chính thức của hàm. Trong trường hợp này, các thay đổi được thực hiện đối với tham số bên trong hàm không ảnh hưởng đến đối số.

2 Gọi bằng con trỏ

Phương thức này sao chép địa chỉ của một đối số vào tham số chính thức. Bên trong hàm, địa chỉ được sử dụng để truy cập đối số thực được sử dụng trong lệnh gọi. Điều này có nghĩa là các thay đổi được thực hiện đối với tham số sẽ ảnh hưởng đến đối số.

3 Gọi bằng tham chiếu

Phương thức này sao chép tham chiếu của một đối số vào tham số chính thức. Bên trong hàm, tham chiếu được sử dụng để truy cập đối số thực được sử dụng trong lệnh gọi. Điều này có nghĩa là các thay đổi được thực hiện đối với tham số sẽ ảnh hưởng đến đối số.

Theo mặc định, C ++ sử dụng call by valueđể chuyển đối số. Nói chung, điều này có nghĩa là mã bên trong một hàm không thể thay đổi các đối số được sử dụng để gọi hàm và ví dụ đã đề cập ở trên trong khi gọi hàm max () được sử dụng cùng một phương thức.

Giá trị mặc định cho các tham số

Khi bạn xác định một hàm, bạn có thể chỉ định một giá trị mặc định cho mỗi tham số cuối cùng. Giá trị này sẽ được sử dụng nếu đối số tương ứng bị bỏ trống khi gọi hàm.

Điều này được thực hiện bằng cách sử dụng toán tử gán và gán giá trị cho các đối số trong định nghĩa hàm. Nếu một giá trị cho tham số đó không được chuyển khi hàm được gọi, giá trị đã cho mặc định sẽ được sử dụng, nhưng nếu một giá trị được chỉ định, giá trị mặc định này sẽ bị bỏ qua và giá trị đã truyền được sử dụng thay thế. Hãy xem xét ví dụ sau:

#include <iostream>
using namespace std;
 
int sum(int a, int b = 20) {
   int result;
   result = a + b;
  
   return (result);
}
int main () {
   // local variable declaration:
   int a = 100;
   int b = 200;
   int result;
 
   // calling a function to add the values.
   result = sum(a, b);
   cout << "Total value is :" << result << endl;

   // calling a function again as follows.
   result = sum(a);
   cout << "Total value is :" << result << endl;
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total value is :300
Total value is :120

Thông thường, khi chúng ta làm việc với Numbers, chúng ta sử dụng các kiểu dữ liệu nguyên thủy như int, short, long, float và double, v.v. Các kiểu dữ liệu số, giá trị có thể có và phạm vi số đã được giải thích trong khi thảo luận về Kiểu dữ liệu C ++.

Định nghĩa số trong C ++

Bạn đã xác định các số trong các ví dụ khác nhau được đưa ra trong các chương trước. Đây là một ví dụ tổng hợp khác để xác định các loại số khác nhau trong C ++ -

#include <iostream>
using namespace std;
 
int main () {
   // number definition:
   short  s;
   int    i;
   long   l;
   float  f;
   double d;
   
   // number assignments;
   s = 10;      
   i = 1000;    
   l = 1000000; 
   f = 230.47;  
   d = 30949.374;
   
   // number printing;
   cout << "short  s :" << s << endl;
   cout << "int    i :" << i << endl;
   cout << "long   l :" << l << endl;
   cout << "float  f :" << f << endl;
   cout << "double d :" << d << endl;
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

short  s :10
int    i :1000
long   l :1000000
float  f :230.47
double d :30949.4

Các phép toán trong C ++

Ngoài các chức năng khác nhau mà bạn có thể tạo, C ++ cũng bao gồm một số chức năng hữu ích mà bạn có thể sử dụng. Các hàm này có sẵn trong các thư viện C và C ++ chuẩn và được gọi làbuilt-inchức năng. Đây là những chức năng có thể được đưa vào chương trình của bạn và sau đó sử dụng.

C ++ có một tập hợp các phép toán phong phú, có thể được thực hiện trên nhiều số khác nhau. Bảng sau liệt kê một số hàm toán học tích hợp hữu ích có sẵn trong C ++.

Để sử dụng các hàm này, bạn cần bao gồm tệp tiêu đề toán học <cmath>.

Sr.No Chức năng & Mục đích
1

double cos(double);

Hàm này nhận một góc (như một nhân đôi) và trả về cosin.

2

double sin(double);

Hàm này nhận một góc (như một góc gấp đôi) và trả về sin.

3

double tan(double);

Hàm này nhận một góc (như một góc gấp đôi) và trả về tiếp tuyến.

4

double log(double);

Hàm này nhận một số và trả về nhật ký tự nhiên của số đó.

5

double pow(double, double);

Đầu tiên là một con số bạn muốn nâng lên và thứ hai là sức mạnh bạn muốn nâng nó lên t

6

double hypot(double, double);

Nếu bạn chuyển hàm này độ dài hai cạnh của một tam giác vuông, nó sẽ trả về cho bạn độ dài cạnh huyền.

7

double sqrt(double);

Bạn chuyển cho hàm này một số và nó cung cấp cho bạn căn bậc hai.

số 8

int abs(int);

Hàm này trả về giá trị tuyệt đối của một số nguyên được chuyển cho nó.

9

double fabs(double);

Hàm này trả về giá trị tuyệt đối của bất kỳ số thập phân nào được chuyển đến nó.

10

double floor(double);

Tìm số nguyên nhỏ hơn hoặc bằng đối số được truyền cho nó.

Sau đây là một ví dụ đơn giản để chỉ ra một số phép toán:

#include <iostream>
#include <cmath>
using namespace std;
 
int main () {
   // number definition:
   short  s = 10;
   int    i = -1000;
   long   l = 100000;
   float  f = 230.47;
   double d = 200.374;

   // mathematical operations;
   cout << "sin(d) :" << sin(d) << endl;
   cout << "abs(i)  :" << abs(i) << endl;
   cout << "floor(d) :" << floor(d) << endl;
   cout << "sqrt(f) :" << sqrt(f) << endl;
   cout << "pow( d, 2) :" << pow(d, 2) << endl;
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

sign(d)     :-0.634939
abs(i)      :1000
floor(d)    :200
sqrt(f)     :15.1812
pow( d, 2 ) :40149.7

Số ngẫu nhiên trong C ++

Có nhiều trường hợp bạn muốn tạo một số ngẫu nhiên. Thực tế có hai hàm bạn sẽ cần biết về việc tạo số ngẫu nhiên. Đầu tiên làrand(), hàm này sẽ chỉ trả về một số ngẫu nhiên giả. Cách khắc phục điều này trước tiên là gọisrand() chức năng.

Sau đây là một ví dụ đơn giản để tạo ra một vài số ngẫu nhiên. Ví dụ này sử dụngtime() hàm để lấy số giây trên thời gian hệ thống của bạn, để tạo ngẫu nhiên hàm rand () -

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;
 
int main () {
   int i,j;
 
   // set the seed
   srand( (unsigned)time( NULL ) );

   /* generate 10  random numbers. */
   for( i = 0; i < 10; i++ ) {
      // generate actual random number
      j = rand();
      cout <<" Random Number : " << j << endl;
   }

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Random Number : 1748144778
Random Number : 630873888
Random Number : 2134540646
Random Number : 219404170
Random Number : 902129458
Random Number : 920445370
Random Number : 1319072661
Random Number : 257938873
Random Number : 1256201101
Random Number : 580322989

C ++ cung cấp một cấu trúc dữ liệu, the array, nơi lưu trữ một tập hợp tuần tự có kích thước cố định của các phần tử cùng loại. Mảng được sử dụng để lưu trữ một tập hợp dữ liệu, nhưng thường hữu ích hơn nếu coi một mảng là một tập hợp các biến cùng kiểu.

Thay vì khai báo các biến riêng lẻ, chẳng hạn như number0, number1, ... và number99, bạn khai báo một biến mảng chẳng hạn như số và sử dụng số [0], số [1] và ..., số [99] để biểu diễn các biến riêng lẻ. Một phần tử cụ thể trong một mảng được truy cập bởi một chỉ mục.

Tất cả các mảng bao gồm các vị trí bộ nhớ liền nhau. Địa chỉ thấp nhất tương ứng với phần tử đầu tiên và địa chỉ cao nhất cho phần tử cuối cùng.

Khai báo Mảng

Để khai báo một mảng trong C ++, lập trình viên chỉ định kiểu của các phần tử và số phần tử theo yêu cầu của một mảng như sau:

type arrayName [ arraySize ];

Đây được gọi là mảng một chiều. CácarraySize phải là một hằng số nguyên lớn hơn 0 và typecó thể là bất kỳ kiểu dữ liệu C ++ hợp lệ nào. Ví dụ, để khai báo một mảng 10 phần tử được gọi là số dư kiểu double, hãy sử dụng câu lệnh này:

double balance[10];

Khởi tạo Mảng

Bạn có thể khởi tạo từng phần tử mảng C ++ hoặc sử dụng một câu lệnh như sau:

double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Số lượng giá trị giữa các dấu ngoặc vuông {} không được lớn hơn số phần tử mà chúng ta khai báo cho mảng giữa các dấu ngoặc vuông []. Sau đây là một ví dụ để gán một phần tử duy nhất của mảng:

Nếu bạn bỏ qua kích thước của mảng, một mảng vừa đủ lớn để chứa quá trình khởi tạo sẽ được tạo. Do đó, nếu bạn viết -

double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Bạn sẽ tạo chính xác mảng giống như bạn đã làm trong ví dụ trước.

balance[4] = 50.0;

Các chuyển nhượng tuyên bố số lượng phần tử 5 trên thứ trong mảng giá trị là 50,0. Mảng có chỉ số thứ 4 sẽ là thứ 5 , tức là phần tử cuối cùng vì tất cả các mảng đều có 0 là chỉ số của phần tử đầu tiên của chúng, còn được gọi là chỉ số cơ sở. Sau đây là đại diện bằng hình ảnh của cùng một mảng mà chúng ta đã thảo luận ở trên -

Truy cập các phần tử mảng

Một phần tử được truy cập bằng cách đánh chỉ mục tên mảng. Điều này được thực hiện bằng cách đặt chỉ mục của phần tử trong dấu ngoặc vuông sau tên của mảng. Ví dụ -

double salary = balance[9];

Câu lệnh trên sẽ lấy phần tử thứ 10 từ mảng và gán giá trị cho biến lương. Sau đây là một ví dụ, sẽ sử dụng tất cả ba khái niệm được đề cập ở trên viz. khai báo, gán và truy cập mảng -

#include <iostream>
using namespace std;
 
#include <iomanip>
using std::setw;
 
int main () {

   int n[ 10 ]; // n is an array of 10 integers
 
   // initialize elements of array n to 0          
   for ( int i = 0; i < 10; i++ ) {
      n[ i ] = i + 100; // set element at location i to i + 100
   }
   cout << "Element" << setw( 13 ) << "Value" << endl;
 
   // output each array element's value                      
   for ( int j = 0; j < 10; j++ ) {
      cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
   }
 
   return 0;
}

Chương trình này sử dụng setw()chức năng định dạng đầu ra. Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Element        Value
      0          100
      1          101
      2          102
      3          103
      4          104
      5          105
      6          106
      7          107
      8          108
      9          109

Mảng trong C ++

Mảng rất quan trọng đối với C ++ và cần nhiều chi tiết hơn. Có một vài khái niệm quan trọng sau đây mà một lập trình viên C ++ cần phải rõ ràng -

Sr.No Khái niệm & Mô tả
1 Mảng đa chiều

C ++ hỗ trợ mảng nhiều chiều. Dạng đơn giản nhất của mảng nhiều chiều là mảng hai chiều.

2 Con trỏ đến một mảng

Bạn có thể tạo một con trỏ đến phần tử đầu tiên của mảng bằng cách chỉ định tên mảng mà không cần bất kỳ chỉ mục nào.

3 Truyền mảng cho các hàm

Bạn có thể chuyển cho hàm một con trỏ tới một mảng bằng cách chỉ định tên của mảng mà không có chỉ mục.

4 Trả về mảng từ các hàm

C ++ cho phép một hàm trả về một mảng.

C ++ cung cấp hai kiểu biểu diễn chuỗi sau:

  • Chuỗi ký tự kiểu C.
  • Kiểu lớp chuỗi được giới thiệu với Standard C ++.

Chuỗi ký tự kiểu C

Chuỗi ký tự kiểu C bắt nguồn từ ngôn ngữ C và tiếp tục được hỗ trợ trong C ++. Chuỗi này thực sự là một mảng một chiều các ký tự được kết thúc bằngnullký tự '\ 0'. Do đó, một chuỗi được kết thúc bằng null chứa các ký tự bao gồm chuỗi theo sau bởi mộtnull.

Khai báo và khởi tạo sau tạo một chuỗi bao gồm từ "Hello". Để giữ ký tự rỗng ở cuối mảng, kích thước của mảng ký tự chứa chuỗi lớn hơn một lần số ký tự trong từ "Xin chào".

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

Nếu bạn tuân theo quy tắc khởi tạo mảng, thì bạn có thể viết câu lệnh trên như sau:

char greeting[] = "Hello";

Sau đây là phần trình bày bộ nhớ của chuỗi được xác định ở trên trong C / C ++ -

Trên thực tế, bạn không đặt ký tự null ở cuối một hằng chuỗi. Trình biên dịch C ++ tự động đặt '\ 0' vào cuối chuỗi khi nó khởi tạo mảng. Hãy để chúng tôi cố gắng in chuỗi nói trên -

#include <iostream>

using namespace std;

int main () {

   char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

   cout << "Greeting message: ";
   cout << greeting << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Greeting message: Hello

C ++ hỗ trợ một loạt các hàm thao tác với các chuỗi bị kết thúc bằng null -

Sr.No Chức năng & Mục đích
1

strcpy(s1, s2);

Sao chép chuỗi s2 thành chuỗi s1.

2

strcat(s1, s2);

Nối chuỗi s2 vào cuối chuỗi s1.

3

strlen(s1);

Trả về độ dài của chuỗi s1.

4

strcmp(s1, s2);

Trả về 0 nếu s1 và s2 giống nhau; nhỏ hơn 0 nếu s1 <s2; lớn hơn 0 nếu s1> s2.

5

strchr(s1, ch);

Trả về một con trỏ đến lần xuất hiện đầu tiên của ký tự ch trong chuỗi s1.

6

strstr(s1, s2);

Trả về một con trỏ đến lần xuất hiện đầu tiên của chuỗi s2 trong chuỗi s1.

Ví dụ sau sử dụng một vài hàm được đề cập ở trên:

#include <iostream>
#include <cstring>

using namespace std;

int main () {

   char str1[10] = "Hello";
   char str2[10] = "World";
   char str3[10];
   int  len ;

   // copy str1 into str3
   strcpy( str3, str1);
   cout << "strcpy( str3, str1) : " << str3 << endl;

   // concatenates str1 and str2
   strcat( str1, str2);
   cout << "strcat( str1, str2): " << str1 << endl;

   // total lenghth of str1 after concatenation
   len = strlen(str1);
   cout << "strlen(str1) : " << len << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10

Lớp chuỗi trong C ++

Thư viện C ++ tiêu chuẩn cung cấp một stringloại lớp hỗ trợ tất cả các hoạt động được đề cập ở trên, bổ sung nhiều chức năng hơn. Hãy để chúng tôi kiểm tra ví dụ sau:

#include <iostream>
#include <string>

using namespace std;

int main () {

   string str1 = "Hello";
   string str2 = "World";
   string str3;
   int  len ;

   // copy str1 into str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;

   // concatenates str1 and str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;

   // total length of str3 after concatenation
   len = str3.size();
   cout << "str3.size() :  " << len << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

str3 : Hello
str1 + str2 : HelloWorld
str3.size() :  10

Con trỏ C ++ rất dễ học và thú vị. Một số tác vụ C ++ được thực hiện dễ dàng hơn với con trỏ và các tác vụ C ++ khác, chẳng hạn như cấp phát bộ nhớ động, không thể thực hiện được nếu không có chúng.

Như bạn đã biết, mọi biến đều là một vị trí bộ nhớ và mọi vị trí bộ nhớ đều có địa chỉ của nó được xác định có thể được truy cập bằng cách sử dụng toán tử dấu và (&) biểu thị một địa chỉ trong bộ nhớ. Hãy xem xét phần sau sẽ in ra địa chỉ của các biến được xác định:

#include <iostream>

using namespace std;
int main () {
   int  var1;
   char var2[10];

   cout << "Address of var1 variable: ";
   cout << &var1 << endl;

   cout << "Address of var2 variable: ";
   cout << &var2 << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Address of var1 variable: 0xbfebd5c0
Address of var2 variable: 0xbfebd5b6

Con trỏ là gì?

A pointerlà một biến có giá trị là địa chỉ của một biến khác. Giống như bất kỳ biến hoặc hằng số nào, bạn phải khai báo một con trỏ trước khi bạn có thể làm việc với nó. Dạng chung của khai báo biến con trỏ là:

type *var-name;

Đây, typelà kiểu cơ sở của con trỏ; nó phải là loại C ++ hợp lệ vàvar-namelà tên của biến con trỏ. Dấu hoa thị bạn đã sử dụng để khai báo một con trỏ giống với dấu hoa thị mà bạn sử dụng cho phép nhân. Tuy nhiên, trong câu lệnh này, dấu hoa thị được sử dụng để chỉ định một biến làm con trỏ. Sau đây là khai báo con trỏ hợp lệ:

int    *ip;    // pointer to an integer
double *dp;    // pointer to a double
float  *fp;    // pointer to a float
char   *ch     // pointer to character

Kiểu dữ liệu thực tế của giá trị của tất cả các con trỏ, cho dù là số nguyên, số thực, ký tự hay cách khác, đều giống nhau, một số thập lục phân dài đại diện cho địa chỉ bộ nhớ. Sự khác biệt duy nhất giữa các con trỏ của các kiểu dữ liệu khác nhau là kiểu dữ liệu của biến hoặc hằng số mà con trỏ trỏ tới.

Sử dụng con trỏ trong C ++

Có một số thao tác quan trọng mà chúng tôi sẽ thực hiện với các con trỏ rất thường xuyên. (a) Chúng tôi xác định một biến con trỏ. (b) Gán địa chỉ của một biến cho một con trỏ. (c)Cuối cùng là truy cập giá trị tại địa chỉ có sẵn trong biến con trỏ. Điều này được thực hiện bằng cách sử dụng toán tử một ngôi * trả về giá trị của biến nằm tại địa chỉ được chỉ định bởi toán hạng của nó. Ví dụ sau sử dụng các thao tác này:

#include <iostream>

using namespace std;

int main () {
   int  var = 20;   // actual variable declaration.
   int  *ip;        // pointer variable 

   ip = &var;       // store address of var in pointer variable

   cout << "Value of var variable: ";
   cout << var << endl;

   // print the address stored in ip pointer variable
   cout << "Address stored in ip variable: ";
   cout << ip << endl;

   // access the value at the address available in pointer
   cout << "Value of *ip variable: ";
   cout << *ip << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20

Con trỏ trong C ++

Con trỏ có nhiều khái niệm nhưng dễ và chúng rất quan trọng đối với lập trình C ++. Có một vài khái niệm con trỏ quan trọng sau đây mà một lập trình viên C ++ phải rõ ràng:

Sr.No Khái niệm & Mô tả
1 Con trỏ rỗng

C ++ hỗ trợ con trỏ null, là một hằng số có giá trị bằng 0 được xác định trong một số thư viện tiêu chuẩn.

2 Số học con trỏ

Có bốn toán tử số học có thể được sử dụng trên con trỏ: ++, -, +, -

3 Con trỏ so với Mảng

Có một mối quan hệ chặt chẽ giữa con trỏ và mảng.

4 Mảng con trỏ

Bạn có thể xác định mảng để chứa một số con trỏ.

5 Con trỏ tới con trỏ

C ++ cho phép bạn có con trỏ trên một con trỏ, v.v.

6 Chuyển con trỏ đến các hàm

Truyền một đối số theo tham chiếu hoặc theo địa chỉ đều cho phép đối số đã truyền được thay đổi trong hàm gọi bởi hàm được gọi.

7 Con trỏ trả về từ các hàm

C ++ cho phép một hàm trả về một con trỏ tới biến cục bộ, biến tĩnh và cả bộ nhớ được cấp phát động.

Một biến tham chiếu là một bí danh, tức là một tên khác của một biến đã tồn tại. Khi một tham chiếu được khởi tạo với một biến, tên biến hoặc tên tham chiếu có thể được sử dụng để tham chiếu đến biến.

Tham chiếu so với Con trỏ

Tham chiếu thường bị nhầm lẫn với con trỏ nhưng ba điểm khác biệt chính giữa tham chiếu và con trỏ là:

  • Bạn không thể có tham chiếu NULL. Bạn phải luôn có thể giả định rằng một tham chiếu được kết nối với một phần lưu trữ hợp pháp.

  • Khi một tham chiếu được khởi tạo cho một đối tượng, nó không thể được thay đổi để tham chiếu đến một đối tượng khác. Con trỏ có thể được trỏ đến một đối tượng khác bất cứ lúc nào.

  • Tham chiếu phải được khởi tạo khi nó được tạo. Con trỏ có thể được khởi tạo bất kỳ lúc nào.

Tạo tài liệu tham khảo trong C ++

Hãy nghĩ về một tên biến như một nhãn gắn với vị trí của biến trong bộ nhớ. Sau đó, bạn có thể coi một tham chiếu như một nhãn thứ hai được gắn vào vị trí bộ nhớ đó. Do đó, bạn có thể truy cập nội dung của biến thông qua tên biến ban đầu hoặc tham chiếu. Ví dụ, giả sử chúng ta có ví dụ sau:

int i = 17;

Chúng ta có thể khai báo các biến tham chiếu cho i như sau.

int& r = i;

Đọc & trong các khai báo này như reference. Do đó, hãy đọc khai báo đầu tiên là "r là tham chiếu số nguyên được khởi tạo thành i" và đọc khai báo thứ hai là "s là tham chiếu kép được khởi tạo thành d.". Ví dụ sau sử dụng các tham chiếu trên int và double -

#include <iostream>
 
using namespace std;
 
int main () {
   // declare simple variables
   int    i;
   double d;
 
   // declare reference variables
   int&    r = i;
   double& s = d;
   
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
 
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   
   return 0;
}

Khi đoạn mã trên được biên dịch cùng nhau và được thực thi, nó sẽ tạo ra kết quả sau:

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

Tham chiếu thường được sử dụng cho danh sách đối số hàm và giá trị trả về của hàm. Vì vậy, sau đây là hai chủ đề quan trọng liên quan đến tài liệu tham khảo C ++ mà một lập trình viên C ++ cần phải hiểu rõ:

Sr.No Khái niệm & Mô tả
1 Tham chiếu dưới dạng tham số

C ++ hỗ trợ truyền tham chiếu dưới dạng tham số hàm an toàn hơn tham số.

2 Tham chiếu dưới dạng Giá trị trả lại

Bạn có thể trả về tham chiếu từ một hàm C ++ giống như bất kỳ kiểu dữ liệu nào khác.

Thư viện chuẩn C ++ không cung cấp kiểu ngày tháng thích hợp. C ++ kế thừa các cấu trúc và hàm cho thao tác ngày và giờ từ C. Để truy cập các hàm và cấu trúc liên quan đến ngày và giờ, bạn cần phải bao gồm tệp tiêu đề <ctime> trong chương trình C ++ của mình.

Có bốn loại liên quan đến thời gian: clock_t, time_t, size_ttm. Các kiểu - clock_t, size_t và time_t có khả năng biểu diễn ngày và giờ của hệ thống dưới dạng một số loại số nguyên.

Loại cấu trúc tm giữ ngày và giờ ở dạng cấu trúc C có các phần tử sau:

struct tm {
   int tm_sec;   // seconds of minutes from 0 to 61
   int tm_min;   // minutes of hour from 0 to 59
   int tm_hour;  // hours of day from 0 to 24
   int tm_mday;  // day of month from 1 to 31
   int tm_mon;   // month of year from 0 to 11
   int tm_year;  // year since 1900
   int tm_wday;  // days since sunday
   int tm_yday;  // days since January 1st
   int tm_isdst; // hours of daylight savings time
}

Sau đây là các hàm quan trọng, chúng tôi sử dụng khi làm việc với ngày và giờ trong C hoặc C ++. Tất cả các hàm này là một phần của thư viện C và C ++ chuẩn và bạn có thể kiểm tra chi tiết của chúng bằng cách sử dụng tham chiếu đến thư viện chuẩn C ++ được cung cấp bên dưới.

Sr.No Chức năng & Mục đích
1

time_t time(time_t *time);

Điều này trả về thời gian lịch hiện tại của hệ thống theo số giây đã trôi qua kể từ ngày 1 tháng 1 năm 1970. Nếu hệ thống không có thời gian, thì .1 được trả về.

2

char *ctime(const time_t *time);

Điều này trả về một con trỏ đến một chuỗi có dạng ngày tháng năm giờ: phút: giây năm \ n \ 0 .

3

struct tm *localtime(const time_t *time);

Điều này trả về một con trỏ đến tm cấu trúc đại diện cho giờ địa phương.

4

clock_t clock(void);

Giá trị này trả về một giá trị gần đúng với khoảng thời gian chương trình gọi đã chạy. Giá trị .1 được trả về nếu thời gian không có sẵn.

5

char * asctime ( const struct tm * time );

Điều này trả về một con trỏ đến một chuỗi chứa thông tin được lưu trữ trong cấu trúc được trỏ đến theo thời gian được chuyển đổi thành dạng: ngày tháng ngày giờ: phút: giây năm \ n \ 0

6

struct tm *gmtime(const time_t *time);

Điều này trả về một con trỏ đến thời gian ở dạng cấu trúc tm. Thời gian được biểu thị bằng Giờ phối hợp quốc tế (UTC), về cơ bản là Giờ trung bình Greenwich (GMT).

7

time_t mktime(struct tm *time);

Điều này trả về lịch-thời gian tương đương với thời gian được tìm thấy trong cấu trúc được trỏ đến theo thời gian.

số 8

double difftime ( time_t time2, time_t time1 );

Hàm này tính toán sự khác biệt theo giây giữa time1 và time2.

9

size_t strftime();

Chức năng này có thể được sử dụng để định dạng ngày và giờ theo một định dạng cụ thể.

Ngày và giờ hiện tại

Giả sử bạn muốn truy xuất ngày và giờ hệ thống hiện tại, dưới dạng giờ địa phương hoặc là Giờ Phối hợp Quốc tế (UTC). Sau đây là ví dụ để đạt được điều tương tự -

#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);
   
   // convert now to string form
   char* dt = ctime(&now);

   cout << "The local date and time is: " << dt << endl;

   // convert now to tm struct for UTC
   tm *gmtm = gmtime(&now);
   dt = asctime(gmtm);
   cout << "The UTC date and time is:"<< dt << endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

The local date and time is: Sat Jan  8 20:07:41 2011

The UTC date and time is:Sun Jan  9 03:07:41 2011

Định dạng thời gian sử dụng cấu trúc tm

Các tmcấu trúc rất quan trọng khi làm việc với ngày và giờ trong C hoặc C ++. Cấu trúc này giữ ngày và giờ ở dạng cấu trúc C như đã nói ở trên. Hầu hết các chức năng liên quan đến thời gian sử dụng cấu trúc tm. Sau đây là một ví dụ sử dụng các hàm khác nhau liên quan đến ngày giờ và cấu trúc tm -

Trong khi sử dụng cấu trúc trong chương này, tôi giả định rằng bạn đã hiểu cơ bản về cấu trúc C và cách truy cập các thành viên cấu trúc bằng cách sử dụng toán tử arrow ->.

#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);

   cout << "Number of sec since January 1,1970 is:: " << now << endl;

   tm *ltm = localtime(&now);

   // print various components of tm structure.
   cout << "Year:" << 1900 + ltm->tm_year<<endl;
   cout << "Month: "<< 1 + ltm->tm_mon<< endl;
   cout << "Day: "<< ltm->tm_mday << endl;
   cout << "Time: "<< 5+ltm->tm_hour << ":";
   cout << 30+ltm->tm_min << ":";
   cout << ltm->tm_sec << endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Number of sec since January 1,1970 is:: 1588485717
Year:2020
Month: 5
Day: 3
Time: 11:31:57

Các thư viện tiêu chuẩn C ++ cung cấp một tập hợp các khả năng đầu vào / đầu ra phong phú mà chúng ta sẽ thấy trong các chương tiếp theo. Chương này sẽ thảo luận về các hoạt động I / O rất cơ bản và phổ biến nhất cần thiết cho lập trình C ++.

C ++ I / O xảy ra trong các luồng, là chuỗi các byte. Nếu các byte chảy từ một thiết bị như bàn phím, ổ đĩa hoặc kết nối mạng, v.v. đến bộ nhớ chính, thì điều này được gọi làinput operation và nếu các byte chuyển từ bộ nhớ chính đến một thiết bị như màn hình hiển thị, máy in, ổ đĩa hoặc kết nối mạng, v.v., thì điều này được gọi là output operation.

Tệp tiêu đề thư viện I / O

Có các tệp tiêu đề sau quan trọng đối với các chương trình C ++:

Sr.No Tệp tiêu đề & Chức năng và Mô tả
1

<iostream>

Tệp này xác định cin, cout, cerrclog các đối tượng, tương ứng với luồng đầu vào tiêu chuẩn, luồng đầu ra tiêu chuẩn, luồng lỗi tiêu chuẩn không được đệm và luồng lỗi tiêu chuẩn có đệm, tương ứng.

2

<iomanip>

Tệp này khai báo các dịch vụ hữu ích để thực hiện I / O được định dạng với cái gọi là trình thao tác luồng được tham số hóa, chẳng hạn như setwsetprecision.

3

<fstream>

Tệp này khai báo các dịch vụ xử lý tệp do người dùng kiểm soát. Chúng ta sẽ thảo luận chi tiết về nó trong chương liên quan đến Tệp và Luồng.

Luồng đầu ra tiêu chuẩn (cout)

Đối tượng được xác định trước cout là một ví dụ của ostreamlớp học. Đối tượng cout được cho là "kết nối với" thiết bị đầu ra tiêu chuẩn, thường là màn hình hiển thị. Cáccout được sử dụng cùng với toán tử chèn luồng, được viết dưới dạng << là hai dấu nhỏ hơn như thể hiện trong ví dụ sau.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Hello C++";
 
   cout << "Value of str is : " << str << endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Value of str is : Hello C++

Trình biên dịch C ++ cũng xác định kiểu dữ liệu của biến được xuất ra và chọn toán tử chèn luồng thích hợp để hiển thị giá trị. Toán tử << được nạp chồng để xuất ra các mục dữ liệu của các kiểu có sẵn giá trị nguyên, float, double, string và con trỏ.

Toán tử chèn << có thể được sử dụng nhiều lần trong một câu lệnh như được hiển thị ở trên và endl được sử dụng để thêm một dòng mới vào cuối dòng.

Luồng đầu vào chuẩn (cin)

Đối tượng được xác định trước cin là một ví dụ của istreamlớp học. Đối tượng cin được cho là được gắn vào thiết bị nhập tiêu chuẩn, thường là bàn phím. Cáccin được sử dụng kết hợp với toán tử trích xuất luồng, được viết là >> là hai dấu lớn hơn như thể hiện trong ví dụ sau.

#include <iostream>
 
using namespace std;
 
int main() {
   char name[50];
 
   cout << "Please enter your name: ";
   cin >> name;
   cout << "Your name is: " << name << endl;
 
}

Khi đoạn mã trên được biên dịch và thực thi, nó sẽ nhắc bạn nhập tên. Bạn nhập một giá trị rồi nhấn enter để xem kết quả sau:

Please enter your name: cplusplus
Your name is: cplusplus

Trình biên dịch C ++ cũng xác định kiểu dữ liệu của giá trị đã nhập và chọn toán tử trích xuất dòng thích hợp để trích xuất giá trị và lưu trữ trong các biến đã cho.

Toán tử trích xuất luồng >> có thể được sử dụng nhiều lần trong một câu lệnh. Để yêu cầu nhiều hơn một dữ liệu, bạn có thể sử dụng như sau:

cin >> name >> age;

Điều này sẽ tương đương với hai câu lệnh sau:

cin >> name;
cin >> age;

Luồng lỗi chuẩn (cerr)

Đối tượng được xác định trước cerr là một ví dụ của ostreamlớp học. Đối tượng cerr được cho là gắn vào thiết bị lỗi chuẩn, cũng là một màn hình hiển thị nhưng đối tượngcerr không được lưu vào bộ đệm và mỗi lần chèn luồng vào chứng chỉ sẽ khiến đầu ra của nó xuất hiện ngay lập tức.

Các cerr cũng được sử dụng cùng với toán tử chèn luồng như trong ví dụ sau.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   cerr << "Error message : " << str << endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Error message : Unable to read....

Luồng nhật ký chuẩn (tắc nghẽn)

Đối tượng được xác định trước clog là một ví dụ của ostreamlớp học. Đối tượng tắc nghẽn được cho là gắn vào thiết bị lỗi chuẩn, cũng là một màn hình hiển thị nhưng đối tượngclogđược đệm. Điều này có nghĩa là mỗi lần chèn để làm tắc nghẽn có thể khiến đầu ra của nó bị giữ trong bộ đệm cho đến khi bộ đệm được lấp đầy hoặc cho đến khi bộ đệm được xả sạch.

Các clog cũng được sử dụng cùng với toán tử chèn luồng như trong ví dụ sau.

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   clog << "Error message : " << str << endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Error message : Unable to read....

Bạn sẽ không thể thấy bất kỳ sự khác biệt nào về cout, cerr và clog với những ví dụ nhỏ này, nhưng trong khi viết và thực thi các chương trình lớn, sự khác biệt trở nên rõ ràng. Vì vậy, thực hành tốt là hiển thị thông báo lỗi bằng luồng cerr và trong khi hiển thị các thông báo nhật ký khác thì nên sử dụng tắc nghẽn.

Mảng C / C ++ cho phép bạn xác định các biến kết hợp một số mục dữ liệu cùng loại, nhưng structure là một kiểu dữ liệu khác do người dùng xác định cho phép bạn kết hợp các mục dữ liệu thuộc các loại khác nhau.

Cấu trúc được sử dụng để đại diện cho một bản ghi, giả sử bạn muốn theo dõi sách của mình trong thư viện. Bạn có thể muốn theo dõi các thuộc tính sau về mỗi cuốn sách -

  • Title
  • Author
  • Subject
  • Mã sách

Xác định cấu trúc

Để xác định một cấu trúc, bạn phải sử dụng câu lệnh struct. Câu lệnh struct xác định một kiểu dữ liệu mới, với nhiều hơn một thành viên, cho chương trình của bạn. Định dạng của câu lệnh struct là:

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

Các structure taglà tùy chọn và mỗi định nghĩa thành viên là một định nghĩa biến bình thường, chẳng hạn như int i; hoặc float f; hoặc bất kỳ định nghĩa biến hợp lệ nào khác. Ở cuối định nghĩa của cấu trúc, trước dấu chấm phẩy cuối cùng, bạn có thể chỉ định một hoặc nhiều biến cấu trúc nhưng nó là tùy chọn. Đây là cách bạn khai báo cấu trúc Sách -

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

Truy cập thành viên cấu trúc

Để truy cập bất kỳ thành viên nào của một cấu trúc, chúng tôi sử dụng member access operator (.). Toán tử truy cập thành viên được mã hóa là dấu chấm giữa tên biến cấu trúc và thành viên cấu trúc mà chúng ta muốn truy cập. Bạn sẽ sử dụngstructtừ khóa để xác định các biến của kiểu cấu trúc. Sau đây là ví dụ để giải thích cách sử dụng cấu trúc:

#include <iostream>
#include <cstring>
 
using namespace std;
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info
   cout << "Book 1 title : " << Book1.title <<endl;
   cout << "Book 1 author : " << Book1.author <<endl;
   cout << "Book 1 subject : " << Book1.subject <<endl;
   cout << "Book 1 id : " << Book1.book_id <<endl;

   // Print Book2 info
   cout << "Book 2 title : " << Book2.title <<endl;
   cout << "Book 2 author : " << Book2.author <<endl;
   cout << "Book 2 subject : " << Book2.subject <<endl;
   cout << "Book 2 id : " << Book2.book_id <<endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700

Cấu trúc dưới dạng đối số hàm

Bạn có thể truyền một cấu trúc như một đối số của hàm theo cách tương tự như khi bạn truyền bất kỳ biến hoặc con trỏ nào khác. Bạn sẽ truy cập các biến cấu trúc theo cách tương tự như bạn đã truy cập trong ví dụ trên -

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books book );

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info
   printBook( Book1 );

   // Print Book2 info
   printBook( Book2 );

   return 0;
}
void printBook( struct Books book ) {
   cout << "Book title : " << book.title <<endl;
   cout << "Book author : " << book.author <<endl;
   cout << "Book subject : " << book.subject <<endl;
   cout << "Book id : " << book.book_id <<endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

Con trỏ đến cấu trúc

Bạn có thể xác định con trỏ đến cấu trúc theo cách tương tự như bạn định nghĩa con trỏ cho bất kỳ biến nào khác như sau:

struct Books *struct_pointer;

Bây giờ, bạn có thể lưu trữ địa chỉ của một biến cấu trúc trong biến con trỏ đã xác định ở trên. Để tìm địa chỉ của một biến cấu trúc, hãy đặt toán tử & trước tên của cấu trúc như sau:

struct_pointer = &Book1;

Để truy cập các thành viên của một cấu trúc bằng cách sử dụng con trỏ đến cấu trúc đó, bạn phải sử dụng toán tử -> như sau:

struct_pointer->title;

Hãy để chúng tôi viết lại ví dụ trên bằng cách sử dụng con trỏ cấu trúc, hy vọng điều này sẽ dễ dàng cho bạn hiểu khái niệm -

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books *book );

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
int main() {
   struct Books Book1;        // Declare Book1 of type Book
   struct Books Book2;        // Declare Book2 of type Book
 
   // Book 1 specification
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // Book 2 specification
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // Print Book1 info, passing address of structure
   printBook( &Book1 );

   // Print Book1 info, passing address of structure
   printBook( &Book2 );

   return 0;
}

// This function accept pointer to structure as parameter.
void printBook( struct Books *book ) {
   cout << "Book title : " << book->title <<endl;
   cout << "Book author : " << book->author <<endl;
   cout << "Book subject : " << book->subject <<endl;
   cout << "Book id : " << book->book_id <<endl;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

Từ khóa typedef

Có một cách dễ dàng hơn để xác định cấu trúc hoặc bạn có thể tạo các loại "bí danh". Ví dụ -

typedef struct {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Books;

Bây giờ, bạn có thể sử dụng Sách trực tiếp để xác định các biến của loại Sách mà không cần sử dụng từ khóa struct. Sau đây là ví dụ -

Books Book1, Book2;

Bạn có thể dùng typedef từ khóa cho không phải cấu trúc cũng như sau:

typedef long int *pint32;
 
pint32 x, y, z;

x, y và z đều là con trỏ đến số nguyên dài.

Mục đích chính của lập trình C ++ là thêm hướng đối tượng vào ngôn ngữ lập trình C và các lớp là tính năng trung tâm của C ++ hỗ trợ lập trình hướng đối tượng và thường được gọi là kiểu do người dùng định nghĩa.

Một lớp được sử dụng để chỉ định dạng của một đối tượng và nó kết hợp biểu diễn dữ liệu và các phương thức để thao tác dữ liệu đó thành một gói gọn gàng. Dữ liệu và các hàm trong một lớp được gọi là thành viên của lớp.

Định nghĩa lớp C ++

Khi bạn xác định một lớp, bạn xác định một bản thiết kế cho một kiểu dữ liệu. Điều này không thực sự xác định bất kỳ dữ liệu nào, nhưng nó xác định ý nghĩa của tên lớp, nghĩa là, một đối tượng của lớp sẽ bao gồm những gì và những thao tác nào có thể được thực hiện trên một đối tượng như vậy.

Định nghĩa lớp bắt đầu bằng từ khóa classtiếp theo là tên lớp; và phần thân của lớp, được bao bởi một cặp dấu ngoặc nhọn. Định nghĩa lớp phải được theo sau bởi dấu chấm phẩy hoặc danh sách các khai báo. Ví dụ: chúng tôi đã xác định kiểu dữ liệu Hộp bằng từ khóaclass như sau -

class Box {
   public:
      double length;   // Length of a box
      double breadth;  // Breadth of a box
      double height;   // Height of a box
};

Từ khóa publicxác định các thuộc tính truy cập của các thành viên của lớp theo sau nó. Một thành viên công cộng có thể được truy cập từ bên ngoài lớp ở bất kỳ đâu trong phạm vi của đối tượng lớp. Bạn cũng có thể chỉ định các thành viên của một lớp làprivate hoặc là protected mà chúng ta sẽ thảo luận trong một phần phụ.

Xác định các đối tượng C ++

Một lớp cung cấp bản thiết kế cho các đối tượng, vì vậy về cơ bản một đối tượng được tạo ra từ một lớp. Chúng ta khai báo các đối tượng của một lớp với kiểu khai báo giống hệt như chúng ta khai báo các biến kiểu cơ bản. Các câu lệnh sau khai báo hai đối tượng của lớp Box:

Box Box1;          // Declare Box1 of type Box
Box Box2;          // Declare Box2 of type Box

Cả hai đối tượng Box1 và Box2 sẽ có bản sao dữ liệu của riêng chúng.

Truy cập các thành viên dữ liệu

Các thành viên dữ liệu công khai của các đối tượng của một lớp có thể được truy cập bằng toán tử truy cập thành viên trực tiếp (.). Chúng ta hãy thử ví dụ sau để làm rõ mọi thứ -

#include <iostream>

using namespace std;

class Box {
   public:
      double length;   // Length of a box
      double breadth;  // Breadth of a box
      double height;   // Height of a box
};

int main() {
   Box Box1;        // Declare Box1 of type Box
   Box Box2;        // Declare Box2 of type Box
   double volume = 0.0;     // Store the volume of a box here
 
   // box 1 specification
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;

   // box 2 specification
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
   
   // volume of box 1
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Volume of Box1 : " << volume <<endl;

   // volume of box 2
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Volume of Box2 : " << volume <<endl;
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Volume of Box1 : 210
Volume of Box2 : 1560

Điều quan trọng cần lưu ý là không thể truy cập trực tiếp các thành viên riêng tư và được bảo vệ bằng cách sử dụng toán tử truy cập thành viên trực tiếp (.). Chúng tôi sẽ tìm hiểu cách các thành viên được bảo vệ và riêng tư có thể được truy cập.

Chi tiết các lớp và đối tượng

Cho đến nay, bạn đã có ý tưởng rất cơ bản về các Lớp và Đối tượng C ++. Có những khái niệm thú vị khác liên quan đến Lớp và Đối tượng C ++ mà chúng ta sẽ thảo luận trong các phần phụ khác nhau được liệt kê bên dưới:

Sr.No Khái niệm & Mô tả
1 Chức năng của thành viên trong lớp

Hàm thành viên của một lớp là một hàm có định nghĩa hoặc nguyên mẫu của nó trong định nghĩa lớp giống như bất kỳ biến nào khác.

2 Công cụ sửa đổi quyền truy cập lớp học

Một thành viên trong lớp có thể được định nghĩa là công khai, riêng tư hoặc được bảo vệ. Theo mặc định, các thành viên sẽ được coi là riêng tư.

3 Khối tạo & Bộ hủy

Hàm tạo lớp là một hàm đặc biệt trong lớp được gọi khi một đối tượng mới của lớp được tạo. Hàm hủy cũng là một hàm đặc biệt được gọi khi đối tượng đã tạo bị xóa.

4 Copy Constructor

Phương thức khởi tạo sao chép là một phương thức khởi tạo tạo một đối tượng bằng cách khởi tạo nó với một đối tượng cùng lớp, đã được tạo trước đó.

5 Chức năng bạn bè

A friend chức năng được phép truy cập đầy đủ vào các thành viên riêng tư và được bảo vệ của một lớp.

6 Chức năng nội tuyến

Với một hàm nội tuyến, trình biên dịch cố gắng mở rộng mã trong phần thân của hàm thay cho lời gọi hàm.

7 Con trỏ này

Mỗi đối tượng đều có một con trỏ đặc biệt this mà trỏ đến chính đối tượng.

số 8 Con trỏ đến các lớp C ++

Một con trỏ tới một lớp được thực hiện giống hệt như cách con trỏ tới một cấu trúc. Trong thực tế, một lớp thực sự chỉ là một cấu trúc với các chức năng trong đó.

9 Thành viên tĩnh của một lớp

Cả thành viên dữ liệu và thành viên hàm của một lớp đều có thể được khai báo là tĩnh.

Một trong những khái niệm quan trọng nhất trong lập trình hướng đối tượng là tính kế thừa. Tính kế thừa cho phép chúng ta định nghĩa một lớp theo nghĩa của một lớp khác, giúp tạo và duy trì một ứng dụng dễ dàng hơn. Điều này cũng tạo cơ hội để sử dụng lại chức năng mã và thời gian thực hiện nhanh chóng.

Khi tạo một lớp, thay vì viết các thành viên dữ liệu hoàn toàn mới và các hàm thành viên, lập trình viên có thể chỉ định rằng lớp mới sẽ kế thừa các thành viên của một lớp hiện có. Lớp hiện có này được gọi làbase lớp và lớp mới được gọi là derived lớp học.

Ý tưởng kế thừa thực hiện is amối quan hệ. Ví dụ, động vật IS-A động vật có vú, chó IS-A động vật có vú, do đó chó IS-A động vật cũng như vậy.

Các lớp cơ sở và có nguồn gốc

Một lớp có thể được dẫn xuất từ ​​nhiều lớp, có nghĩa là nó có thể kế thừa dữ liệu và chức năng từ nhiều lớp cơ sở. Để định nghĩa một lớp dẫn xuất, chúng tôi sử dụng danh sách dẫn xuất lớp để chỉ định (các) lớp cơ sở. Một danh sách dẫn xuất lớp đặt tên cho một hoặc nhiều lớp cơ sở và có dạng:

class derived-class: access-specifier base-class

Trong đó công cụ chỉ định truy cập là một trong những public, protected, hoặc là private, và lớp cơ sở là tên của một lớp đã được xác định trước đó. Nếu thông số truy cập không được sử dụng, thì nó là riêng tư theo mặc định.

Xem xét một lớp cơ sở Shape và lớp dẫn xuất của nó Rectangle như sau -

#include <iostream>
 
using namespace std;

// Base class
class Shape {
   public:
      void setWidth(int w) {
         width = w;
      }
      void setHeight(int h) {
         height = h;
      }
      
   protected:
      int width;
      int height;
};

// Derived class
class Rectangle: public Shape {
   public:
      int getArea() { 
         return (width * height); 
      }
};

int main(void) {
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);

   // Print the area of the object.
   cout << "Total area: " << Rect.getArea() << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total area: 35

Kiểm soát truy cập và kế thừa

Một lớp dẫn xuất có thể truy cập tất cả các thành viên không riêng tư của lớp cơ sở của nó. Do đó, các thành viên lớp cơ sở không thể truy cập vào các hàm thành viên của các lớp dẫn xuất nên được khai báo là private trong lớp cơ sở.

Chúng tôi có thể tóm tắt các kiểu truy cập khác nhau theo - ai có thể truy cập chúng theo cách sau -

Truy cập công cộng được bảo vệ riêng tư
Cùng lớp Đúng Đúng Đúng
Các lớp có nguồn gốc Đúng Đúng Không
Các lớp học bên ngoài Đúng Không Không

Một lớp dẫn xuất kế thừa tất cả các phương thức của lớp cơ sở với các ngoại lệ sau:

  • Các hàm tạo, hàm hủy và sao chép các hàm tạo của lớp cơ sở.
  • Các toán tử bị quá tải của lớp cơ sở.
  • Các hàm friend của lớp cơ sở.

Loại thừa kế

Khi dẫn xuất một lớp từ một lớp cơ sở, lớp cơ sở có thể được kế thừa thông qua public, protected hoặc là privatedi sản. Kiểu kế thừa được chỉ định bởi access-specifier như đã giải thích ở trên.

Chúng tôi hầu như không sử dụng protected hoặc là private thừa kế, nhưng publickế thừa được sử dụng phổ biến. Trong khi sử dụng loại kế thừa khác, các quy tắc sau được áp dụng:

  • Public Inheritance - Khi dẫn xuất một lớp từ một public lớp cơ sở, public các thành viên của lớp cơ sở trở thành public các thành viên của lớp dẫn xuất và protected các thành viên của lớp cơ sở trở thành protectedcác thành viên của lớp dẫn xuất. Một lớp cơ sởprivate các thành viên không bao giờ có thể truy cập trực tiếp từ một lớp dẫn xuất, nhưng có thể được truy cập thông qua các lệnh gọi đến publicprotected các thành viên của lớp cơ sở.

  • Protected Inheritance - Khi xuất phát từ một protected lớp cơ sở, publicprotected các thành viên của lớp cơ sở trở thành protected các thành viên của lớp dẫn xuất.

  • Private Inheritance - Khi xuất phát từ một private lớp cơ sở, publicprotected các thành viên của lớp cơ sở trở thành private các thành viên của lớp dẫn xuất.

Nhiều người thừa kế

Một lớp C ++ có thể kế thừa các thành viên từ nhiều hơn một lớp và đây là cú pháp mở rộng:

class derived-class: access baseA, access baseB....

Nơi truy cập là một trong những public, protected, hoặc là privatevà sẽ được cung cấp cho mọi lớp cơ sở và chúng sẽ được phân tách bằng dấu phẩy như hình trên. Hãy để chúng tôi thử ví dụ sau:

#include <iostream>
 
using namespace std;

// Base class Shape
class Shape {
   public:
      void setWidth(int w) {
         width = w;
      }
      void setHeight(int h) {
         height = h;
      }
      
   protected:
      int width;
      int height;
};

// Base class PaintCost
class PaintCost {
   public:
      int getCost(int area) {
         return area * 70;
      }
};

// Derived class
class Rectangle: public Shape, public PaintCost {
   public:
      int getArea() {
         return (width * height); 
      }
};

int main(void) {
   Rectangle Rect;
   int area;
 
   Rect.setWidth(5);
   Rect.setHeight(7);

   area = Rect.getArea();
   
   // Print the area of the object.
   cout << "Total area: " << Rect.getArea() << endl;

   // Print the total cost of painting
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total area: 35
Total paint cost: $2450

C ++ cho phép bạn chỉ định nhiều hơn một định nghĩa cho một function tên hoặc một operator trong cùng một phạm vi, được gọi là function overloadingoperator overloading tương ứng.

Khai báo quá tải là một khai báo được khai báo cùng tên với một khai báo đã khai báo trước đó trong cùng một phạm vi, ngoại trừ việc cả hai khai báo có các đối số khác nhau và rõ ràng là khác nhau về định nghĩa (thực thi).

Khi bạn gọi một quá tải function hoặc là operator, trình biên dịch xác định định nghĩa phù hợp nhất để sử dụng, bằng cách so sánh các kiểu đối số bạn đã sử dụng để gọi hàm hoặc toán tử với các kiểu tham số được chỉ định trong định nghĩa. Quá trình chọn hàm hoặc toán tử được nạp chồng thích hợp nhất được gọi làoverload resolution.

Nạp chồng hàm trong C ++

Bạn có thể có nhiều định nghĩa cho cùng một tên hàm trong cùng một phạm vi. Định nghĩa của hàm phải khác nhau theo kiểu và / hoặc số lượng đối số trong danh sách đối số. Bạn không thể nạp chồng các khai báo hàm chỉ khác nhau theo kiểu trả về.

Sau đây là ví dụ trong đó cùng một chức năng print() đang được sử dụng để in các kiểu dữ liệu khác nhau -

#include <iostream>
using namespace std;
 
class printData {
   public:
      void print(int i) {
        cout << "Printing int: " << i << endl;
      }
      void print(double  f) {
        cout << "Printing float: " << f << endl;
      }
      void print(char* c) {
        cout << "Printing character: " << c << endl;
      }
};

int main(void) {
   printData pd;
 
   // Call print to print integer
   pd.print(5);
   
   // Call print to print float
   pd.print(500.263);
   
   // Call print to print character
   pd.print("Hello C++");
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Printing int: 5
Printing float: 500.263
Printing character: Hello C++

Nạp chồng toán tử trong C ++

Bạn có thể xác định lại hoặc quá tải hầu hết các toán tử tích hợp sẵn có trong C ++. Do đó, một lập trình viên cũng có thể sử dụng các toán tử với các kiểu do người dùng xác định.

Toán tử được nạp chồng là những hàm có tên đặc biệt: từ khóa "toán tử" theo sau là ký hiệu cho toán tử đang được định nghĩa. Giống như bất kỳ hàm nào khác, toán tử được nạp chồng có kiểu trả về và danh sách tham số.

Box operator+(const Box&);

khai báo toán tử bổ sung có thể được sử dụng để addhai đối tượng Box và trả về đối tượng Box cuối cùng. Hầu hết các toán tử được nạp chồng có thể được định nghĩa là các hàm không phải thành viên thông thường hoặc như các hàm thành viên lớp. Trong trường hợp chúng ta định nghĩa hàm trên là hàm không phải là thành viên của một lớp thì chúng ta sẽ phải chuyển hai đối số cho mỗi toán hạng như sau:

Box operator+(const Box&, const Box&);

Sau đây là ví dụ để hiển thị khái niệm toán tử vượt tải bằng cách sử dụng một hàm thành viên. Ở đây một đối tượng được truyền dưới dạng một đối số mà các thuộc tính sẽ được truy cập bằng cách sử dụng đối tượng này, đối tượng sẽ gọi toán tử này có thể được truy cập bằng cách sử dụngthis toán tử như được giải thích bên dưới -

#include <iostream>
using namespace std;

class Box {
   public:
      double getVolume(void) {
         return length * breadth * height;
      }
      void setLength( double len ) {
         length = len;
      }
      void setBreadth( double bre ) {
         breadth = bre;
      }
      void setHeight( double hei ) {
         height = hei;
      }
      
      // Overload + operator to add two Box objects.
      Box operator+(const Box& b) {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }
      
   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

// Main function for the program
int main() {
   Box Box1;                // Declare Box1 of type Box
   Box Box2;                // Declare Box2 of type Box
   Box Box3;                // Declare Box3 of type Box
   double volume = 0.0;     // Store the volume of a box here
 
   // box 1 specification
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   // box 2 specification
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // volume of box 1
   volume = Box1.getVolume();
   cout << "Volume of Box1 : " << volume <<endl;
 
   // volume of box 2
   volume = Box2.getVolume();
   cout << "Volume of Box2 : " << volume <<endl;

   // Add two object as follows:
   Box3 = Box1 + Box2;

   // volume of box 3
   volume = Box3.getVolume();
   cout << "Volume of Box3 : " << volume <<endl;

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

Có thể quá tải / Không thể quá tải

Sau đây là danh sách các toán tử có thể được nạp chồng:

+ - * / % ^
& | ~ ! , =
< > <= > = ++ -
<< >> == ! = && ||
+ = - = / = % = ^ = & =
| = * = << = >> = [] ()
-> -> * Mới Mới [] xóa bỏ xóa bỏ []

Sau đây là danh sách các toán tử, không thể được nạp chồng:

:: . * . ?:

Ví dụ về quá tải của nhà điều hành

Dưới đây là các ví dụ nạp chồng toán tử khác nhau để giúp bạn hiểu khái niệm này.

Sr.No Toán tử & Ví dụ
1 Quá tải các nhà khai thác đơn lẻ
2 Quá tải toán tử nhị phân
3 Quá tải các toán tử quan hệ
4 Quá tải toán tử đầu vào / đầu ra
5 ++ và - Quá tải toán tử
6 Quá tải người điều hành nhiệm vụ
7 Lệnh gọi hàm () Nạp chồng toán tử
số 8 Đăng ký [] Người vận hành quá tải
9 Toán tử Quyền truy cập Thành viên Lớp -> Quá tải

Từ polymorphismnghĩa là có nhiều hình thức. Thông thường, tính đa hình xảy ra khi có một hệ thống phân cấp của các lớp và chúng có liên quan với nhau bởi tính kế thừa.

Tính đa hình trong C ++ có nghĩa là một lệnh gọi đến một hàm thành viên sẽ khiến một hàm khác được thực thi tùy thuộc vào loại đối tượng gọi hàm.

Hãy xem xét ví dụ sau trong đó một lớp cơ sở đã được dẫn xuất bởi hai lớp khác:

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }
      int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};

// Main function for the program
int main() {
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // store the address of Rectangle
   shape = &rec;
   
   // call rectangle area.
   shape->area();

   // store the address of Triangle
   shape = &tri;
   
   // call triangle area.
   shape->area();
   
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Parent class area :
Parent class area :

Lý do cho kết quả đầu ra không chính xác là lời gọi của vùng hàm () đang được trình biên dịch đặt một lần làm phiên bản được định nghĩa trong lớp cơ sở. Đây được gọi làstatic resolution của lệnh gọi hàm, hoặc static linkage- lệnh gọi hàm được cố định trước khi chương trình được thực thi. Điều này đôi khi cũng được gọi làearly binding vì hàm area () được thiết lập trong quá trình biên dịch chương trình.

Nhưng bây giờ, chúng ta hãy thực hiện một sửa đổi nhỏ trong chương trình của chúng ta và bắt đầu khai báo vùng () trong lớp Shape với từ khóa virtual để nó trông như thế này -

class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      virtual int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

Sau sửa đổi nhỏ này, khi mã ví dụ trước đó được biên dịch và thực thi, nó tạo ra kết quả sau:

Rectangle class area
Triangle class area

Lần này, trình biên dịch xem xét nội dung của con trỏ thay vì kiểu của nó. Do đó, vì địa chỉ của các đối tượng thuộc các lớp tri và rec được lưu trữ trong * shape nên hàm area () tương ứng được gọi.

Như bạn có thể thấy, mỗi lớp con có một triển khai riêng cho vùng hàm (). Đây là cáchpolymorphismthường được sử dụng. Bạn có các lớp khác nhau với một hàm có cùng tên, và thậm chí là các tham số giống nhau, nhưng với các cách triển khai khác nhau.

Chức năng ảo

A virtual function là một hàm trong lớp cơ sở được khai báo bằng từ khóa virtual. Định nghĩa trong lớp cơ sở một hàm ảo, với một phiên bản khác trong lớp dẫn xuất, báo hiệu cho trình biên dịch rằng chúng ta không muốn liên kết tĩnh cho hàm này.

Những gì chúng ta muốn là lựa chọn hàm được gọi tại bất kỳ điểm nhất định nào trong chương trình để dựa trên loại đối tượng mà nó được gọi. Loại hoạt động này được gọi làdynamic linkage, hoặc là late binding.

Chức năng ảo thuần túy

Có thể bạn muốn đưa một hàm ảo vào một lớp cơ sở để nó có thể được định nghĩa lại trong một lớp dẫn xuất cho phù hợp với các đối tượng của lớp đó, nhưng không có định nghĩa có ý nghĩa nào mà bạn có thể đưa ra cho hàm trong lớp cơ sở .

Chúng ta có thể thay đổi vùng hàm ảo () trong lớp cơ sở thành như sau:

class Shape {
   protected:
      int width, height;

   public:
      Shape(int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      
      // pure virtual function
      virtual int area() = 0;
};

= 0 cho trình biên dịch biết rằng hàm không có nội dung và hàm ảo ở trên sẽ được gọi pure virtual function.

Trừu tượng hóa dữ liệu đề cập đến việc chỉ cung cấp thông tin cần thiết cho thế giới bên ngoài và che giấu các chi tiết cơ bản của chúng, tức là để thể hiện thông tin cần thiết trong chương trình mà không trình bày chi tiết.

Trừu tượng hóa dữ liệu là một kỹ thuật lập trình (và thiết kế) dựa trên sự tách biệt giữa giao diện và việc triển khai.

Hãy lấy một ví dụ thực tế về TV, bạn có thể bật và tắt, thay đổi kênh, điều chỉnh âm lượng và thêm các thành phần bên ngoài như loa, VCR và đầu đĩa DVD, NHƯNG bạn không biết chi tiết bên trong của nó, là, bạn không biết làm thế nào nó nhận được tín hiệu qua không khí hoặc qua cáp, cách nó dịch chúng và cuối cùng hiển thị chúng trên màn hình.

Vì vậy, chúng ta có thể nói rằng một chiếc tivi tách biệt rõ ràng việc triển khai bên trong của nó với giao diện bên ngoài và bạn có thể chơi với các giao diện của nó như nút nguồn, bộ đổi kênh và điều khiển âm lượng mà không cần biết gì về bên trong của nó.

Trong C ++, các lớp cung cấp mức độ data abstraction. Chúng cung cấp đủ các phương thức công khai cho thế giới bên ngoài để chơi với chức năng của đối tượng và thao tác dữ liệu đối tượng, tức là trạng thái mà không thực sự biết lớp đã được triển khai bên trong như thế nào.

Ví dụ: chương trình của bạn có thể thực hiện cuộc gọi đến sort()hàm mà không biết hàm thực sự sử dụng thuật toán nào để sắp xếp các giá trị đã cho. Trên thực tế, việc triển khai cơ bản của chức năng sắp xếp có thể thay đổi giữa các bản phát hành của thư viện và miễn là giao diện vẫn giữ nguyên, lệnh gọi hàm của bạn sẽ vẫn hoạt động.

Trong C ++, chúng tôi sử dụng classesđể xác định các kiểu dữ liệu trừu tượng (ADT) của riêng chúng ta. Bạn có thể dùngcout đối tượng của lớp ostream để truyền dữ liệu đến đầu ra tiêu chuẩn như thế này -

#include <iostream>
using namespace std;

int main() {
   cout << "Hello C++" <<endl;
   return 0;
}

Ở đây, bạn không cần phải hiểu cách couthiển thị văn bản trên màn hình của người dùng. Bạn chỉ cần biết giao diện công khai và việc triển khai cơ bản của 'cout' có thể tự do thay đổi.

Truy cập Nhãn Thực thi Tóm tắt

Trong C ++, chúng ta sử dụng các nhãn truy cập để xác định giao diện trừu tượng cho lớp. Một lớp có thể chứa không hoặc nhiều nhãn truy cập -

  • Các thành viên được xác định với nhãn công khai có thể truy cập được vào tất cả các phần của chương trình. Dạng xem trừu tượng hóa dữ liệu của một kiểu được xác định bởi các thành viên công khai của nó.

  • Các thành viên được xác định với nhãn riêng không thể truy cập vào mã sử dụng lớp. Các phần riêng tư ẩn việc triển khai khỏi mã sử dụng loại.

Không có hạn chế về tần suất một nhãn truy cập có thể xuất hiện. Mỗi nhãn truy cập chỉ định mức truy cập của các định nghĩa thành viên kế tiếp. Mức truy cập đã chỉ định vẫn có hiệu lực cho đến khi gặp nhãn truy cập tiếp theo hoặc dấu ngoặc nhọn đóng bên phải của phần thân lớp.

Lợi ích của việc trừu tượng hóa dữ liệu

Sự trừu tượng hóa dữ liệu cung cấp hai lợi thế quan trọng:

  • Nội bộ lớp được bảo vệ khỏi các lỗi cấp người dùng không cố ý, có thể làm hỏng trạng thái của đối tượng.

  • Việc triển khai lớp có thể phát triển theo thời gian để đáp ứng với các yêu cầu thay đổi hoặc báo cáo lỗi mà không yêu cầu thay đổi mã cấp người dùng.

Bằng cách chỉ định nghĩa các thành viên dữ liệu trong phần riêng tư của lớp, tác giả của lớp có thể tự do thực hiện các thay đổi trong dữ liệu. Nếu việc triển khai thay đổi, chỉ mã lớp cần được kiểm tra để xem những gì có thể ảnh hưởng đến thay đổi. Nếu dữ liệu là công khai, thì bất kỳ chức năng nào truy cập trực tiếp vào các thành viên dữ liệu của biểu diễn cũ có thể bị hỏng.

Ví dụ về trừu tượng hóa dữ liệu

Bất kỳ chương trình C ++ nào mà bạn triển khai một lớp với các thành viên công khai và riêng tư là một ví dụ về trừu tượng hóa dữ liệu. Hãy xem xét ví dụ sau:

#include <iostream>
using namespace std;

class Adder {
   public:
      // constructor
      Adder(int i = 0) {
         total = i;
      }
      
      // interface to outside world
      void addNum(int number) {
         total += number;
      }
      
      // interface to outside world
      int getTotal() {
         return total;
      };
      
   private:
      // hidden data from outside world
      int total;
};

int main() {
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);

   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total 60

Lớp trên cộng các số lại với nhau và trả về tổng. Các thành viên công cộng -addNumgetTotallà các giao diện với thế giới bên ngoài và người dùng cần biết chúng để sử dụng lớp. Thành viên riêngtotal là thứ mà người dùng không cần biết, nhưng cần thiết để lớp hoạt động bình thường.

Chiến lược thiết kế

Tính trừu tượng phân tách mã thành giao diện và triển khai. Vì vậy, trong khi thiết kế thành phần của bạn, bạn phải giữ giao diện độc lập với việc triển khai để nếu bạn thay đổi triển khai cơ bản thì giao diện sẽ vẫn nguyên vẹn.

Trong trường hợp này, bất kỳ chương trình nào đang sử dụng các giao diện này, chúng sẽ không bị ảnh hưởng và chỉ cần biên dịch lại với cách triển khai mới nhất.

Tất cả các chương trình C ++ đều bao gồm hai yếu tố cơ bản sau:

  • Program statements (code) - Đây là một phần của chương trình thực hiện các hành động và chúng được gọi là các hàm.

  • Program data - Dữ liệu là thông tin của chương trình bị ảnh hưởng bởi các chức năng của chương trình.

Đóng gói là một khái niệm Lập trình hướng đối tượng liên kết dữ liệu và các chức năng thao tác dữ liệu với nhau, đồng thời giữ cho cả hai an toàn khỏi sự can thiệp và lạm dụng từ bên ngoài. Tính năng đóng gói dữ liệu đã dẫn đến khái niệm OOP quan trọng vềdata hiding.

Data encapsulation là cơ chế nhóm dữ liệu và các chức năng sử dụng chúng và data abstraction là một cơ chế chỉ để lộ các giao diện và ẩn các chi tiết triển khai với người dùng.

C ++ hỗ trợ các thuộc tính đóng gói và ẩn dữ liệu thông qua việc tạo ra các kiểu do người dùng xác định, được gọi là classes. Chúng tôi đã nghiên cứu rằng một lớp có thể chứaprivate, protected publiccác thành viên. Theo mặc định, tất cả các mục được định nghĩa trong một lớp là riêng tư. Ví dụ -

class Box {
   public:
      double getVolume(void) {
         return length * breadth * height;
      }

   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

Các biến chiều dài, chiều rộng và chiều cao là private. Điều này có nghĩa là chúng chỉ có thể được truy cập bởi các thành viên khác của lớp Box chứ không phải bất kỳ phần nào khác trong chương trình của bạn. Đây là một cách để đạt được sự đóng gói.

Để tạo ra các phần của một lớp public (tức là, có thể truy cập vào các phần khác của chương trình của bạn), bạn phải khai báo chúng sau publictừ khóa. Tất cả các biến hoặc hàm được xác định sau mã chỉ định công khai đều có thể truy cập được bởi tất cả các hàm khác trong chương trình của bạn.

Việc biến một lớp này thành bạn của lớp khác sẽ làm lộ ra các chi tiết triển khai và giảm bớt tính đóng gói. Lý tưởng là giữ càng nhiều chi tiết của mỗi lớp ẩn với tất cả các lớp khác càng tốt.

Ví dụ về đóng gói dữ liệu

Bất kỳ chương trình C ++ nào mà bạn triển khai một lớp với các thành viên công cộng và riêng tư là một ví dụ về đóng gói dữ liệu và trừu tượng hóa dữ liệu. Hãy xem xét ví dụ sau:

#include <iostream>
using namespace std;

class Adder {
   public:
      // constructor
      Adder(int i = 0) {
         total = i;
      }
      
      // interface to outside world
      void addNum(int number) {
         total += number;
      }
      
      // interface to outside world
      int getTotal() {
         return total;
      };
   
   private:
      // hidden data from outside world
      int total;
};

int main() {
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);

   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total 60

Lớp trên cộng các số lại với nhau và trả về tổng. Các thành viên công cộngaddNumgetTotal là các giao diện với thế giới bên ngoài và người dùng cần biết chúng để sử dụng lớp. Thành viên riêngtotal là một cái gì đó ẩn với thế giới bên ngoài, nhưng cần thiết để lớp hoạt động bình thường.

Chiến lược thiết kế

Hầu hết chúng ta đã học cách đặt các thành viên trong lớp ở chế độ riêng tư theo mặc định trừ khi chúng ta thực sự cần để lộ chúng. Điều đó thật tốtencapsulation.

Điều này được áp dụng thường xuyên nhất cho các thành viên dữ liệu, nhưng nó áp dụng như nhau cho tất cả các thành viên, bao gồm cả các hàm ảo.

Một giao diện mô tả hành vi hoặc khả năng của một lớp C ++ mà không cam kết thực hiện cụ thể của lớp đó.

Các giao diện C ++ được triển khai bằng cách sử dụng abstract classes và các lớp trừu tượng này không nên nhầm lẫn với trừu tượng hóa dữ liệu là một khái niệm giữ các chi tiết triển khai tách biệt với dữ liệu liên quan.

Một lớp được tạo thành trừu tượng bằng cách khai báo ít nhất một trong các hàm của nó như pure virtualchức năng. Một hàm ảo thuần túy được chỉ định bằng cách đặt "= 0" trong khai báo của nó như sau:

class Box {
   public:
      // pure virtual function
      virtual double getVolume() = 0;
      
   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

Mục đích của một abstract class(thường được gọi là ABC) là cung cấp một lớp cơ sở thích hợp mà từ đó các lớp khác có thể kế thừa. Các lớp trừu tượng không thể được sử dụng để khởi tạo các đối tượng và chỉ phục vụ như mộtinterface. Cố gắng khởi tạo một đối tượng của một lớp trừu tượng gây ra lỗi biên dịch.

Do đó, nếu một lớp con của ABC cần được khởi tạo, nó phải thực hiện từng hàm ảo, có nghĩa là nó hỗ trợ giao diện được khai báo bởi ABC. Không thể ghi đè một hàm ảo thuần túy trong một lớp dẫn xuất, sau đó cố gắng khởi tạo các đối tượng của lớp đó, là một lỗi biên dịch.

Các lớp có thể được sử dụng để khởi tạo các đối tượng được gọi là concrete classes.

Ví dụ về lớp trừu tượng

Hãy xem xét ví dụ sau, trong đó lớp cha cung cấp một giao diện cho lớp cơ sở để triển khai một hàm được gọi là getArea() -

#include <iostream>
 
using namespace std;
 
// Base class
class Shape {
   public:
      // pure virtual function providing interface framework.
      virtual int getArea() = 0;
      void setWidth(int w) {
         width = w;
      }
   
      void setHeight(int h) {
         height = h;
      }
   
   protected:
      int width;
      int height;
};
 
// Derived classes
class Rectangle: public Shape {
   public:
      int getArea() { 
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      int getArea() { 
         return (width * height)/2; 
      }
};
 
int main(void) {
   Rectangle Rect;
   Triangle  Tri;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Rectangle area: " << Rect.getArea() << endl;

   Tri.setWidth(5);
   Tri.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Triangle area: " << Tri.getArea() << endl; 

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total Rectangle area: 35
Total Triangle area: 17

Bạn có thể thấy cách một lớp trừu tượng xác định giao diện theo kiểu getArea () và hai lớp khác được thực hiện cùng một hàm nhưng với thuật toán khác nhau để tính toán diện tích cụ thể cho hình dạng.

Chiến lược thiết kế

Một hệ thống hướng đối tượng có thể sử dụng một lớp cơ sở trừu tượng để cung cấp một giao diện chung và chuẩn hóa phù hợp cho tất cả các ứng dụng bên ngoài. Sau đó, thông qua kế thừa từ lớp cơ sở trừu tượng đó, các lớp dẫn xuất được hình thành hoạt động tương tự.

Các khả năng (tức là các chức năng chung) được cung cấp bởi các ứng dụng bên ngoài được cung cấp dưới dạng các chức năng ảo thuần túy trong lớp cơ sở trừu tượng. Việc triển khai các hàm ảo thuần túy này được cung cấp trong các lớp dẫn xuất tương ứng với các kiểu cụ thể của ứng dụng.

Kiến trúc này cũng cho phép các ứng dụng mới được thêm vào hệ thống một cách dễ dàng, ngay cả sau khi hệ thống đã được xác định.

Cho đến nay, chúng tôi đã sử dụng iostream thư viện tiêu chuẩn, cung cấp cincout phương pháp đọc từ đầu vào tiêu chuẩn và ghi vào đầu ra tiêu chuẩn tương ứng.

Hướng dẫn này sẽ dạy bạn cách đọc và ghi từ một tệp. Điều này yêu cầu một thư viện C ++ tiêu chuẩn khác được gọi làfstream, xác định ba kiểu dữ liệu mới -

Sr.No Loại dữ liệu và mô tả
1

ofstream

Kiểu dữ liệu này đại diện cho dòng tệp đầu ra và được sử dụng để tạo tệp và ghi thông tin vào tệp.

2

ifstream

Kiểu dữ liệu này đại diện cho dòng tệp đầu vào và được sử dụng để đọc thông tin từ tệp.

3

fstream

Kiểu dữ liệu này đại diện cho luồng tệp nói chung và có các khả năng của cả dòng và ifstream, có nghĩa là nó có thể tạo tệp, ghi thông tin vào tệp và đọc thông tin từ tệp.

Để thực hiện xử lý tệp trong C ++, các tệp tiêu đề <iostream> và <fstream> phải được bao gồm trong tệp nguồn C ++ của bạn.

Mở tệp

Một tệp phải được mở trước khi bạn có thể đọc hoặc ghi vào tệp. Hoặcofstream hoặc là fstreamđối tượng có thể được sử dụng để mở một tệp để viết. Và đối tượng ifstream được sử dụng để mở tệp chỉ nhằm mục đích đọc.

Sau đây là cú pháp tiêu chuẩn cho hàm open (), là một thành viên của các đối tượng fstream, ifstream và ofstream.

void open(const char *filename, ios::openmode mode);

Ở đây, đối số đầu tiên chỉ định tên và vị trí của tệp sẽ được mở và đối số thứ hai của open() hàm thành viên xác định chế độ mà tệp sẽ được mở.

Sr.No Cờ chế độ & Mô tả
1

ios::app

Chế độ nối. Tất cả đầu ra cho tệp đó sẽ được nối vào cuối.

2

ios::ate

Mở tệp để xuất và di chuyển điều khiển đọc / ghi vào cuối tệp.

3

ios::in

Mở một tập tin để đọc.

4

ios::out

Mở một tệp để viết.

5

ios::trunc

Nếu tệp đã tồn tại, nội dung của tệp sẽ bị cắt bớt trước khi mở tệp.

Bạn có thể kết hợp hai hoặc nhiều giá trị này bằng cách ORnhập chúng với nhau. Ví dụ: nếu bạn muốn mở một tệp ở chế độ ghi và muốn cắt bớt tệp đó trong trường hợp tệp đã tồn tại, sau đây sẽ là cú pháp:

ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

Theo cách tương tự, bạn có thể mở một tệp cho mục đích đọc và ghi như sau:

fstream  afile;
afile.open("file.dat", ios::out | ios::in );

Đóng tệp

Khi một chương trình C ++ kết thúc, nó sẽ tự động xóa tất cả các luồng, giải phóng tất cả bộ nhớ được cấp phát và đóng tất cả các tệp đã mở. Nhưng thông lệ tốt là lập trình viên nên đóng tất cả các tệp đã mở trước khi kết thúc chương trình.

Sau đây là cú pháp tiêu chuẩn cho hàm close (), là một thành viên của các đối tượng fstream, ifstream và ofstream.

void close();

Ghi vào tệp

Trong khi lập trình C ++, bạn ghi thông tin vào tệp từ chương trình của mình bằng toán tử chèn luồng (<<) giống như khi bạn sử dụng toán tử đó để xuất thông tin ra màn hình. Sự khác biệt duy nhất là bạn sử dụngofstream hoặc là fstream đối tượng thay vì cout vật.

Đọc từ một tệp

Bạn đọc thông tin từ một tệp vào chương trình của mình bằng toán tử trích xuất luồng (>>) giống như bạn sử dụng toán tử đó để nhập thông tin từ bàn phím. Sự khác biệt duy nhất là bạn sử dụngifstream hoặc là fstream đối tượng thay vì cin vật.

Đọc và Viết Ví dụ

Sau đây là chương trình C ++ mở một tệp ở chế độ đọc và ghi. Sau khi ghi thông tin do người dùng nhập vào tệp có tên afile.dat, chương trình đọc thông tin từ tệp và xuất ra màn hình -

#include <fstream>
#include <iostream>
using namespace std;
 
int main () {
   char data[100];

   // open a file in write mode.
   ofstream outfile;
   outfile.open("afile.dat");

   cout << "Writing to the file" << endl;
   cout << "Enter your name: "; 
   cin.getline(data, 100);

   // write inputted data into the file.
   outfile << data << endl;

   cout << "Enter your age: "; 
   cin >> data;
   cin.ignore();
   
   // again write inputted data into the file.
   outfile << data << endl;

   // close the opened file.
   outfile.close();

   // open a file in read mode.
   ifstream infile; 
   infile.open("afile.dat"); 
 
   cout << "Reading from the file" << endl; 
   infile >> data; 

   // write the data at the screen.
   cout << data << endl;
   
   // again read the data from the file and display it.
   infile >> data; 
   cout << data << endl; 

   // close the opened file.
   infile.close();

   return 0;
}

Khi mã trên được biên dịch và thực thi, nó tạo ra đầu vào và đầu ra mẫu sau:

$./a.out
Writing to the file
Enter your name: Zara
Enter your age: 9
Reading from the file
Zara
9

Các ví dụ trên sử dụng các hàm bổ sung từ đối tượng cin, như hàm getline () để đọc dòng từ bên ngoài và hàm ignore () để bỏ qua các ký tự thừa còn lại của câu lệnh đọc trước đó.

Con trỏ vị trí tệp

Cả hai istreamostreamcung cấp các chức năng thành viên để định vị lại con trỏ vị trí tệp. Các chức năng thành viên này làseekg ("seek get") cho istream và seekp ("seek put") cho ostream.

Đối số của seekg và seekp thông thường là một số nguyên dài. Đối số thứ hai có thể được chỉ định để chỉ ra hướng tìm kiếm. Hướng tìm kiếm có thể làios::beg (mặc định) để định vị liên quan đến đầu luồng, ios::cur để định vị liên quan đến vị trí hiện tại trong luồng hoặc ios::end để định vị liên quan đến cuối luồng.

Con trỏ vị trí tệp là một giá trị số nguyên chỉ định vị trí trong tệp dưới dạng một số byte từ vị trí bắt đầu của tệp. Một số ví dụ về định vị con trỏ vị trí tệp "get" là:

// position to the nth byte of fileObject (assumes ios::beg)
fileObject.seekg( n );

// position n bytes forward in fileObject
fileObject.seekg( n, ios::cur );

// position n bytes back from end of fileObject
fileObject.seekg( n, ios::end );

// position at end of fileObject
fileObject.seekg( 0, ios::end );

Một ngoại lệ là một vấn đề phát sinh trong quá trình thực hiện một chương trình. Một ngoại lệ C ++ là một phản ứng đối với một trường hợp ngoại lệ phát sinh trong khi chương trình đang chạy, chẳng hạn như nỗ lực chia cho không.

Ngoại lệ cung cấp một cách để chuyển quyền kiểm soát từ một phần của chương trình sang phần khác. Xử lý ngoại lệ C ++ được xây dựng dựa trên ba từ khóa:try, catch,throw.

  • throw- Một chương trình ném ra một ngoại lệ khi một vấn đề xuất hiện. Điều này được thực hiện bằng cách sử dụngthrow từ khóa.

  • catch- Một chương trình bắt một ngoại lệ với một trình xử lý ngoại lệ tại vị trí trong chương trình mà bạn muốn xử lý vấn đề. Cáccatch từ khóa chỉ ra việc bắt một ngoại lệ.

  • try - A trykhối xác định một khối mã mà các ngoại lệ cụ thể sẽ được kích hoạt. Tiếp theo là một hoặc nhiều khối bắt.

Giả sử một khối sẽ tạo ra một ngoại lệ, một phương thức bắt một ngoại lệ bằng cách sử dụng kết hợp trycatchtừ khóa. Một khối try / catch được đặt xung quanh mã có thể tạo ra một ngoại lệ. Mã trong khối try / catch được gọi là mã được bảo vệ và cú pháp để sử dụng try / catch như sau:

try {
   // protected code
} catch( ExceptionName e1 ) {
   // catch block
} catch( ExceptionName e2 ) {
   // catch block
} catch( ExceptionName eN ) {
   // catch block
}

Bạn có thể liệt kê nhiều catch các câu lệnh để nắm bắt các loại ngoại lệ khác nhau trong trường hợp try khối tăng nhiều hơn một ngoại lệ trong các tình huống khác nhau.

Ngoại lệ ném

Các ngoại lệ có thể được ném vào bất kỳ đâu trong một khối mã bằng cách sử dụng throwtuyên bố. Toán hạng của câu lệnh ném xác định kiểu cho ngoại lệ và có thể là bất kỳ biểu thức nào và kiểu kết quả của biểu thức xác định kiểu ngoại lệ được ném ra.

Sau đây là một ví dụ về việc ném một ngoại lệ khi điều kiện chia cho 0 xảy ra:

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

Bắt ngoại lệ

Các catch khối theo sau trykhối bắt bất kỳ ngoại lệ nào. Bạn có thể chỉ định loại ngoại lệ bạn muốn bắt và điều này được xác định bởi khai báo ngoại lệ xuất hiện trong dấu ngoặc đơn theo sau từ khóa catch.

try {
   // protected code
} catch( ExceptionName e ) {
  // code to handle ExceptionName exception
}

Đoạn mã trên sẽ bắt một ngoại lệ ExceptionNamekiểu. Nếu bạn muốn chỉ định rằng khối catch phải xử lý bất kỳ loại ngoại lệ nào được đưa vào khối try, bạn phải đặt dấu chấm lửng, ..., giữa các dấu ngoặc đơn bao quanh khai báo ngoại lệ như sau:

try {
   // protected code
} catch(...) {
  // code to handle any exception
}

Sau đây là một ví dụ, ném một phép chia cho không ngoại lệ và chúng tôi bắt nó trong khối bắt.

#include <iostream>
using namespace std;

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

int main () {
   int x = 50;
   int y = 0;
   double z = 0;
 
   try {
      z = division(x, y);
      cout << z << endl;
   } catch (const char* msg) {
     cerr << msg << endl;
   }

   return 0;
}

Bởi vì chúng tôi đang nêu ra một loại ngoại lệ const char*, vì vậy trong khi bắt ngoại lệ này, chúng ta phải sử dụng const char * trong khối bắt. Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Division by zero condition!

Ngoại lệ tiêu chuẩn C ++

C ++ cung cấp danh sách các ngoại lệ tiêu chuẩn được xác định trong <exception>mà chúng tôi có thể sử dụng trong các chương trình của mình. Chúng được sắp xếp theo phân cấp lớp cha-con được hiển thị bên dưới:

Dưới đây là mô tả nhỏ về từng ngoại lệ được đề cập trong hệ thống phân cấp ở trên -

Sr.No Ngoại lệ & Mô tả
1

std::exception

Một ngoại lệ và lớp cha của tất cả các ngoại lệ C ++ tiêu chuẩn.

2

std::bad_alloc

Điều này có thể được ném bởi new.

3

std::bad_cast

Điều này có thể được ném bởi dynamic_cast.

4

std::bad_exception

Đây là thiết bị hữu ích để xử lý các ngoại lệ không mong muốn trong chương trình C ++.

5

std::bad_typeid

Điều này có thể được ném bởi typeid.

6

std::logic_error

Một ngoại lệ về mặt lý thuyết có thể được phát hiện bằng cách đọc mã.

7

std::domain_error

Đây là một ngoại lệ được đưa ra khi một miền không hợp lệ về mặt toán học được sử dụng.

số 8

std::invalid_argument

Điều này được ném ra do các đối số không hợp lệ.

9

std::length_error

Điều này được ném ra khi một chuỗi std :: quá lớn được tạo.

10

std::out_of_range

Điều này có thể được ném bởi phương thức 'at', ví dụ một std :: vector và std :: bitset <> :: operator [] ().

11

std::runtime_error

Một ngoại lệ về mặt lý thuyết không thể được phát hiện bằng cách đọc mã.

12

std::overflow_error

Điều này được ném ra nếu xảy ra tràn toán học.

13

std::range_error

Điều này xảy ra khi bạn cố gắng lưu trữ một giá trị nằm ngoài phạm vi.

14

std::underflow_error

Điều này được ném ra nếu một quy trình toán học xảy ra.

Xác định ngoại lệ mới

Bạn có thể xác định các ngoại lệ của riêng mình bằng cách kế thừa và ghi đè exceptionchức năng lớp. Sau đây là ví dụ, cho thấy cách bạn có thể sử dụng lớp std :: exception để triển khai ngoại lệ của riêng bạn theo cách chuẩn:

#include <iostream>
#include <exception>
using namespace std;

struct MyException : public exception {
   const char * what () const throw () {
      return "C++ Exception";
   }
};
 
int main() {
   try {
      throw MyException();
   } catch(MyException& e) {
      std::cout << "MyException caught" << std::endl;
      std::cout << e.what() << std::endl;
   } catch(std::exception& e) {
      //Other errors
   }
}

Điều này sẽ tạo ra kết quả sau:

MyException caught
C++ Exception

Đây, what()là một phương thức công khai được cung cấp bởi lớp ngoại lệ và nó đã bị ghi đè bởi tất cả các lớp ngoại lệ con. Điều này trả về nguyên nhân của một ngoại lệ.

Hiểu rõ về cách bộ nhớ động thực sự hoạt động trong C ++ là điều cần thiết để trở thành một lập trình viên C ++ giỏi. Bộ nhớ trong chương trình C ++ của bạn được chia thành hai phần:

  • The stack - Tất cả các biến được khai báo bên trong hàm sẽ chiếm bộ nhớ từ ngăn xếp.

  • The heap - Đây là bộ nhớ không sử dụng của chương trình và có thể được sử dụng để cấp phát động bộ nhớ khi chương trình chạy.

Nhiều khi bạn không biết trước mình sẽ cần bao nhiêu bộ nhớ để lưu thông tin cụ thể trong một biến xác định và kích thước của bộ nhớ cần thiết có thể được xác định tại thời điểm chạy.

Bạn có thể cấp phát bộ nhớ tại thời điểm chạy trong heap cho biến của một kiểu nhất định bằng cách sử dụng một toán tử đặc biệt trong C ++ trả về địa chỉ của không gian được cấp phát. Toán tử này được gọi lànew nhà điều hành.

Nếu bạn không cần bộ nhớ được cấp phát động nữa, bạn có thể sử dụng delete toán tử, loại bỏ cấp phát bộ nhớ đã được cấp phát trước đó bởi toán tử mới.

mới và xóa toán tử

Có cú pháp chung sau đây để sử dụng new toán tử để cấp phát bộ nhớ động cho bất kỳ kiểu dữ liệu nào.

new data-type;

Đây, data-typecó thể là bất kỳ kiểu dữ liệu dựng sẵn nào bao gồm một mảng hoặc bất kỳ kiểu dữ liệu nào do người dùng xác định bao gồm lớp hoặc cấu trúc. Hãy để chúng tôi bắt đầu với các kiểu dữ liệu tích hợp sẵn. Ví dụ, chúng ta có thể xác định một con trỏ để gõ double và sau đó yêu cầu cấp phát bộ nhớ tại thời điểm thực thi. Chúng tôi có thể làm điều này bằng cách sử dụngnew toán tử với các câu lệnh sau:

double* pvalue  = NULL; // Pointer initialized with null
pvalue  = new double;   // Request memory for the variable

Bộ nhớ có thể đã không được cấp phát thành công, nếu bộ nhớ miễn phí đã được sử dụng hết. Vì vậy, bạn nên kiểm tra xem toán tử mới có trả về con trỏ NULL hay không và thực hiện hành động thích hợp như sau:

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "Error: out of memory." <<endl;
   exit(1);
}

Các malloc()hàm từ C, vẫn tồn tại trong C ++, nhưng bạn nên tránh sử dụng hàm malloc (). Ưu điểm chính của new so với malloc () là new không chỉ cấp phát bộ nhớ, mà nó còn xây dựng các đối tượng là mục đích chính của C ++.

Tại bất kỳ thời điểm nào, khi bạn cảm thấy một biến đã được cấp phát động không còn cần thiết nữa, bạn có thể giải phóng bộ nhớ mà nó chiếm trong kho lưu trữ miễn phí bằng toán tử 'delete' như sau:

delete pvalue;        // Release memory pointed to by pvalue

Hãy để chúng tôi đặt các khái niệm ở trên và tạo thành ví dụ sau để cho thấy cách hoạt động của 'mới' và 'xóa' -

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // Pointer initialized with null
   pvalue  = new double;   // Request memory for the variable
 
   *pvalue = 29494.99;     // Store value at allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // free up the memory.

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Value of pvalue : 29495

Phân bổ bộ nhớ động cho mảng

Hãy xem xét bạn muốn cấp phát bộ nhớ cho một mảng ký tự, tức là chuỗi 20 ký tự. Sử dụng cùng một cú pháp mà chúng ta đã sử dụng ở trên, chúng ta có thể cấp phát bộ nhớ động như hình dưới đây.

char* pvalue  = NULL;         // Pointer initialized with null
pvalue  = new char[20];       // Request memory for the variable

Để loại bỏ mảng mà chúng ta vừa tạo, câu lệnh sẽ giống như sau:

delete [] pvalue;             // Delete array pointed to by pvalue

Theo cú pháp chung tương tự của toán tử mới, bạn có thể cấp phát cho một mảng nhiều chiều như sau:

double** pvalue  = NULL;      // Pointer initialized with null 
pvalue  = new double [3][4];  // Allocate memory for a 3x4 array

Tuy nhiên, cú pháp giải phóng bộ nhớ cho mảng đa chiều sẽ vẫn giống như trên:

delete [] pvalue;            // Delete array pointed to by pvalue

Phân bổ bộ nhớ động cho các đối tượng

Các đối tượng không khác gì các kiểu dữ liệu đơn giản. Ví dụ: hãy xem xét đoạn mã sau, nơi chúng ta sẽ sử dụng một mảng các đối tượng để làm rõ khái niệm:

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // Delete array

   return 0;
}

Nếu bạn phân bổ một mảng gồm bốn đối tượng Box, hàm tạo Đơn giản sẽ được gọi bốn lần và tương tự khi xóa các đối tượng này, hàm hủy cũng sẽ được gọi cùng một số lần.

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!

Hãy xem xét một tình huống, khi chúng ta có hai người có cùng tên, Zara, trong cùng một lớp. Bất cứ khi nào chúng ta cần phân biệt chúng chắc chắn chúng ta sẽ phải sử dụng một số thông tin bổ sung cùng với tên của chúng, chẳng hạn như khu vực, nếu chúng sống ở khu vực khác hoặc tên của mẹ hoặc cha của chúng, v.v.

Tình huống tương tự có thể phát sinh trong các ứng dụng C ++ của bạn. Ví dụ: bạn có thể đang viết một số mã có một hàm được gọi là xyz () và có một thư viện khác có sẵn cũng có cùng một hàm xyz (). Bây giờ trình biên dịch không có cách nào biết được phiên bản nào của hàm xyz () mà bạn đang đề cập đến trong mã của mình.

A namespaceđược thiết kế để khắc phục khó khăn này và được sử dụng làm thông tin bổ sung để phân biệt các hàm, lớp, biến tương tự, v.v. có cùng tên có sẵn trong các thư viện khác nhau. Sử dụng không gian tên, bạn có thể xác định ngữ cảnh mà tên được định nghĩa. Về bản chất, một không gian tên xác định một phạm vi.

Xác định không gian tên

Định nghĩa không gian tên bắt đầu bằng từ khóa namespace theo sau là tên không gian tên như sau:

namespace namespace_name {
   // code declarations
}

Để gọi phiên bản hỗ trợ không gian tên của một hàm hoặc biến, hãy thêm vào trước (: :) tên không gian tên như sau:

name::code;  // code could be variable or function.

Hãy để chúng tôi xem cách không gian tên phạm vi các thực thể bao gồm cả biến và hàm -

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
}

// second name space
namespace second_space {
   void func() {
      cout << "Inside second_space" << endl;
   }
}

int main () {
   // Calls function from first name space.
   first_space::func();
   
   // Calls function from second name space.
   second_space::func(); 

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Inside first_space
Inside second_space

Chỉ thị sử dụng

Bạn cũng có thể tránh thêm các không gian tên với using namespacechỉ thị. Chỉ thị này cho trình biên dịch biết rằng mã tiếp theo đang sử dụng tên trong không gian tên được chỉ định. Do đó, không gian tên được ngụ ý cho đoạn mã sau:

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
}

// second name space
namespace second_space {
   void func() {
      cout << "Inside second_space" << endl;
   }
}

using namespace first_space;
int main () {
   // This calls function from first name space.
   func();
   
   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Inside first_space

Chỉ thị 'using' cũng có thể được sử dụng để tham chiếu đến một mục cụ thể trong một không gian tên. Ví dụ: nếu phần duy nhất của không gian tên std mà bạn định sử dụng là cout, bạn có thể tham khảo nó như sau:

using std::cout;

Mã tiếp theo có thể tham chiếu đến cout mà không cần thêm vùng tên, nhưng các mục khác trong std không gian tên vẫn cần phải rõ ràng như sau:

#include <iostream>
using std::cout;

int main () {
   cout << "std::endl is used with std!" << std::endl;
   
   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

std::endl is used with std!

Những cái tên được giới thiệu trong một usingchỉ thị tuân theo các quy tắc phạm vi bình thường. Tên có thể nhìn thấy từ điểm củausingchỉ thị đến cuối phạm vi mà chỉ thị được tìm thấy. Các thực thể có cùng tên được xác định trong phạm vi bên ngoài sẽ bị ẩn.

Không gian tên rõ ràng

Một không gian tên có thể được định nghĩa thành một số phần và vì vậy một không gian tên được tạo thành từ tổng các phần được xác định riêng biệt của nó. Các phần riêng biệt của không gian tên có thể được trải rộng trên nhiều tệp.

Vì vậy, nếu một phần của không gian tên yêu cầu tên được xác định trong tệp khác, tên đó vẫn phải được khai báo. Viết một định nghĩa không gian tên sau đây hoặc xác định một không gian tên mới hoặc thêm các phần tử mới vào một vùng tên hiện có -

namespace namespace_name {
   // code declarations
}

Không gian tên lồng nhau

Không gian tên có thể được lồng vào nhau, nơi bạn có thể xác định một không gian tên bên trong một không gian tên khác như sau:

namespace namespace_name1 {
   // code declarations
   namespace namespace_name2 {
      // code declarations
   }
}

Bạn có thể truy cập các thành viên của không gian tên lồng nhau bằng cách sử dụng các toán tử phân giải như sau:

// to access members of namespace_name2
using namespace namespace_name1::namespace_name2;

// to access members of namespace:name1
using namespace namespace_name1;

Trong các câu lệnh trên, nếu bạn đang sử dụng namespace1, thì nó sẽ làm cho các phần tử của namespace_name2 có sẵn trong phạm vi như sau:

#include <iostream>
using namespace std;

// first name space
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
   
   // second name space
   namespace second_space {
      void func() {
         cout << "Inside second_space" << endl;
      }
   }
}

using namespace first_space::second_space;
int main () {
   // This calls function from second name space.
   func();
   
   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Inside second_space

Mẫu là nền tảng của lập trình chung, liên quan đến việc viết mã theo cách độc lập với bất kỳ kiểu cụ thể nào.

Mẫu là một kế hoạch chi tiết hoặc công thức để tạo một lớp hoặc một hàm chung. Các bộ chứa thư viện như trình lặp và thuật toán là ví dụ về lập trình chung và đã được phát triển bằng cách sử dụng khái niệm mẫu.

Có một định nghĩa duy nhất về mỗi vùng chứa, chẳng hạn như vector, nhưng chúng ta có thể xác định nhiều loại vectơ khác nhau, chẳng hạn như vector <int> hoặc là vector <string>.

Bạn có thể sử dụng các mẫu để xác định các hàm cũng như các lớp, hãy để chúng tôi xem cách chúng hoạt động -

Mẫu hàm

Dạng tổng quát của định nghĩa hàm mẫu được hiển thị ở đây:

template <class type> ret-type func-name(parameter list) {
   // body of function
}

Ở đây, type là tên trình giữ chỗ cho kiểu dữ liệu được hàm sử dụng. Tên này có thể được sử dụng trong định nghĩa hàm.

Sau đây là ví dụ về mẫu hàm trả về giá trị tối đa là hai giá trị:

#include <iostream>
#include <string>

using namespace std;

template <typename T>
inline T const& Max (T const& a, T const& b) { 
   return a < b ? b:a; 
}

int main () {
   int i = 39;
   int j = 20;
   cout << "Max(i, j): " << Max(i, j) << endl; 

   double f1 = 13.5; 
   double f2 = 20.7; 
   cout << "Max(f1, f2): " << Max(f1, f2) << endl; 

   string s1 = "Hello"; 
   string s2 = "World"; 
   cout << "Max(s1, s2): " << Max(s1, s2) << endl; 

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World

Mẫu lớp học

Cũng giống như chúng ta có thể xác định các mẫu hàm, chúng ta cũng có thể xác định các mẫu lớp. Dạng tổng quát của khai báo lớp chung được hiển thị ở đây:

template <class type> class class-name {
   .
   .
   .
}

Đây, typelà tên loại trình giữ chỗ, sẽ được chỉ định khi một lớp được khởi tạo. Bạn có thể xác định nhiều kiểu dữ liệu chung bằng cách sử dụng danh sách được phân tách bằng dấu phẩy.

Sau đây là ví dụ để định nghĩa lớp Stack <> và triển khai các phương thức chung để đẩy và bật các phần tử từ ngăn xếp:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;

template <class T>
class Stack { 
   private: 
      vector<T> elems;    // elements 

   public: 
      void push(T const&);  // push element 
      void pop();               // pop element 
      T top() const;            // return top element 
      
      bool empty() const {      // return true if empty.
         return elems.empty(); 
      } 
}; 

template <class T>
void Stack<T>::push (T const& elem) { 
   // append copy of passed element 
   elems.push_back(elem);    
} 

template <class T>
void Stack<T>::pop () { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::pop(): empty stack"); 
   }
   
   // remove last element 
   elems.pop_back();         
} 

template <class T>
T Stack<T>::top () const { 
   if (elems.empty()) { 
      throw out_of_range("Stack<>::top(): empty stack"); 
   }
   
   // return copy of last element 
   return elems.back();      
} 

int main() { 
   try {
      Stack<int>         intStack;  // stack of ints 
      Stack<string> stringStack;    // stack of strings 

      // manipulate int stack 
      intStack.push(7); 
      cout << intStack.top() <<endl; 

      // manipulate string stack 
      stringStack.push("hello"); 
      cout << stringStack.top() << std::endl; 
      stringStack.pop(); 
      stringStack.pop(); 
   } catch (exception const& ex) { 
      cerr << "Exception: " << ex.what() <<endl; 
      return -1;
   } 
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

7
hello
Exception: Stack<>::pop(): empty stack

Các bộ tiền xử lý là các chỉ thị, cung cấp các chỉ dẫn cho trình biên dịch để xử lý trước thông tin trước khi quá trình biên dịch thực sự bắt đầu.

Tất cả các chỉ thị tiền xử lý bắt đầu bằng # và chỉ các ký tự khoảng trắng mới có thể xuất hiện trước một chỉ thị tiền xử lý trên một dòng. Các chỉ thị tiền xử lý không phải là câu lệnh C ++, vì vậy chúng không kết thúc bằng dấu chấm phẩy (;).

Bạn đã thấy một #includechỉ thị trong tất cả các ví dụ. Macro này được sử dụng để đưa tệp tiêu đề vào tệp nguồn.

Có một số lệnh tiền xử lý được hỗ trợ bởi C ++ như #include, #define, #if, #else, #line, v.v. Hãy để chúng tôi xem các lệnh quan trọng -

#Define Preprocessor

Chỉ thị tiền xử lý #define tạo các hằng số tượng trưng. Hằng số biểu tượng được gọi làmacro và hình thức chung của chỉ thị là -

#define macro-name replacement-text

Khi dòng này xuất hiện trong một tệp, tất cả các lần xuất hiện tiếp theo của macro trong tệp đó sẽ được thay thế bằng văn bản thay thế trước khi chương trình được biên dịch. Ví dụ -

#include <iostream>
using namespace std;

#define PI 3.14159

int main () {
   cout << "Value of PI :" << PI << endl; 

   return 0;
}

Bây giờ, chúng ta hãy thực hiện tiền xử lý mã này để xem kết quả giả sử chúng ta có tệp mã nguồn. Vì vậy, hãy để chúng tôi biên dịch nó với tùy chọn -E và chuyển hướng kết quả đến test.p. Bây giờ, nếu bạn kiểm tra test.p, nó sẽ có rất nhiều thông tin và ở dưới cùng, bạn sẽ thấy giá trị được thay thế như sau:

$gcc -E test.cpp > test.p

...
int main () {
   cout << "Value of PI :" << 3.14159 << endl; 
   return 0;
}

Macro giống hàm

Bạn có thể sử dụng #define để xác định macro sẽ nhận đối số như sau:

#include <iostream>
using namespace std;

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;
   
   cout <<"The minimum is " << MIN(i, j) << endl;

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

The minimum is 30

Biên soạn có điều kiện

Có một số chỉ thị, có thể được sử dụng để biên dịch các phần chọn lọc của mã nguồn chương trình của bạn. Quá trình này được gọi là quá trình biên dịch có điều kiện.

Cấu trúc bộ tiền xử lý có điều kiện giống như cấu trúc lựa chọn 'nếu'. Hãy xem xét mã tiền xử lý sau:

#ifndef NULL
   #define NULL 0
#endif

Bạn có thể biên dịch một chương trình cho mục đích gỡ lỗi. Bạn cũng có thể bật hoặc tắt gỡ lỗi bằng cách sử dụng một macro như sau:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

Điều này gây ra cerrcâu lệnh được biên dịch trong chương trình nếu hằng số tượng trưng DEBUG đã được xác định trước chỉ thị #ifdef DEBUG. Bạn có thể sử dụng trạng thái #if 0 để nhận xét về một phần của chương trình như sau:

#if 0
   code prevented from compiling
#endif

Hãy để chúng tôi thử ví dụ sau:

#include <iostream>
using namespace std;
#define DEBUG

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;

#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif

#if 0
   /* This is commented part */
   cout << MKSTR(HELLO C++) << endl;
#endif

   cout <<"The minimum is " << MIN(i, j) << endl;

#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

The minimum is 30
Trace: Inside main function
Trace: Coming out of main function

Toán tử # và ##

Toán tử tiền xử lý # và ## có sẵn trong C ++ và ANSI / ISO C. Toán tử # khiến mã thông báo văn bản thay thế được chuyển đổi thành một chuỗi được bao quanh bởi dấu ngoặc kép.

Hãy xem xét định nghĩa macro sau:

#include <iostream>
using namespace std;

#define MKSTR( x ) #x

int main () {

   cout << MKSTR(HELLO C++) << endl;

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

HELLO C++

Hãy để chúng tôi xem nó hoạt động như thế nào. Có thể hiểu đơn giản rằng bộ tiền xử lý C ++ biến dòng -

cout << MKSTR(HELLO C++) << endl;

Dòng trên sẽ được chuyển thành dòng sau:

cout << "HELLO C++" << endl;

Toán tử ## được sử dụng để nối hai mã thông báo. Đây là một ví dụ -

#define CONCAT( x, y )  x ## y

Khi CONCAT xuất hiện trong chương trình, các đối số của nó được nối và dùng để thay thế macro. Ví dụ, CONCAT (HELLO, C ++) được thay thế bằng "HELLO C ++" trong chương trình như sau.

#include <iostream>
using namespace std;

#define concat(a, b) a ## b
int main() {
   int xy = 100;
   
   cout << concat(x, y);
   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

100

Hãy để chúng tôi xem nó hoạt động như thế nào. Có thể hiểu đơn giản rằng bộ tiền xử lý C ++ biến đổi -

cout << concat(x, y);

Dòng trên sẽ được chuyển thành dòng sau:

cout << xy;

Macro C ++ được xác định trước

C ++ cung cấp một số macro được xác định trước được đề cập bên dưới:

Sr.No Macro & Mô tả
1

__LINE__

Điều này chứa số dòng hiện tại của chương trình khi nó đang được biên dịch.

2

__FILE__

Điều này chứa tên tệp hiện tại của chương trình khi nó đang được biên dịch.

3

__DATE__

Điều này chứa một chuỗi có dạng tháng / ngày / năm là ngày dịch của tệp nguồn thành mã đối tượng.

4

__TIME__

Điều này chứa một chuỗi có dạng giờ: phút: giây là thời gian chương trình được biên dịch.

Hãy để chúng tôi xem một ví dụ cho tất cả các macro ở trên -

#include <iostream>
using namespace std;

int main () {
   cout << "Value of __LINE__ : " << __LINE__ << endl;
   cout << "Value of __FILE__ : " << __FILE__ << endl;
   cout << "Value of __DATE__ : " << __DATE__ << endl;
   cout << "Value of __TIME__ : " << __TIME__ << endl;

   return 0;
}

Nếu chúng ta biên dịch và chạy đoạn mã trên, điều này sẽ tạo ra kết quả sau:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48

Tín hiệu là các ngắt được hệ điều hành gửi đến một quá trình có thể kết thúc sớm một chương trình. Bạn có thể tạo ngắt bằng cách nhấn Ctrl + C trên hệ thống UNIX, LINUX, Mac OS X hoặc Windows.

Có những tín hiệu mà chương trình không thể bắt được nhưng có một danh sách sau đây các tín hiệu mà bạn có thể bắt được trong chương trình của mình và có thể thực hiện các hành động thích hợp dựa trên tín hiệu đó. Các tín hiệu này được định nghĩa trong tệp tiêu đề C ++ <csignal>.

Sr.No Tín hiệu & Mô tả
1

SIGABRT

Chấm dứt chương trình bất thường, chẳng hạn như cuộc gọi đến abort.

2

SIGFPE

Một phép toán số học sai, chẳng hạn như phép chia cho không hoặc một phép toán dẫn đến tràn.

3

SIGILL

Phát hiện một chỉ dẫn bất hợp pháp.

4

SIGINT

Nhận tín hiệu chú ý tương tác.

5

SIGSEGV

Quyền truy cập không hợp lệ vào bộ nhớ.

6

SIGTERM

Yêu cầu chấm dứt được gửi đến chương trình.

Hàm signal ()

Thư viện xử lý tín hiệu C ++ cung cấp chức năng signalđể bẫy các sự kiện bất ngờ. Sau đây là cú pháp của hàm signal ():

void (*signal (int sig, void (*func)(int)))(int);

Nói một cách đơn giản, hàm này nhận hai đối số: đối số đầu tiên là một số nguyên đại diện cho số tín hiệu và đối số thứ hai là một con trỏ đến hàm xử lý tín hiệu.

Hãy để chúng tôi viết một chương trình C ++ đơn giản, nơi chúng tôi sẽ bắt tín hiệu SIGINT bằng cách sử dụng hàm signal (). Bất kỳ tín hiệu nào bạn muốn bắt trong chương trình của mình, bạn phải đăng ký tín hiệu đó bằngsignalvà kết hợp nó với một trình xử lý tín hiệu. Kiểm tra ví dụ sau -

#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int signum ) {
   cout << "Interrupt signal (" << signum << ") received.\n";

   // cleanup and close up stuff here  
   // terminate program  

   exit(signum);  
}

int main () {
   // register signal SIGINT and signal handler  
   signal(SIGINT, signalHandler);  

   while(1) {
      cout << "Going to sleep...." << endl;
      sleep(1);
   }

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Going to sleep....
Going to sleep....
Going to sleep....

Bây giờ, nhấn Ctrl + c để ngắt chương trình và bạn sẽ thấy rằng chương trình của bạn sẽ bắt được tín hiệu và sẽ xuất hiện bằng cách in ra một thứ như sau:

Going to sleep....
Going to sleep....
Going to sleep....
Interrupt signal (2) received.

Hàm raise ()

Bạn có thể tạo tín hiệu theo chức năng raise(), lấy một số tín hiệu nguyên làm đối số và có cú pháp sau.

int raise (signal sig);

Đây, siglà số tín hiệu để gửi bất kỳ tín hiệu nào: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. Dưới đây là ví dụ mà chúng ta nâng tín hiệu nội bộ bằng cách sử dụng hàm raise () như sau:

#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int signum ) {
   cout << "Interrupt signal (" << signum << ") received.\n";

   // cleanup and close up stuff here  
   // terminate program  

   exit(signum);  
}

int main () {
   int i = 0;
   // register signal SIGINT and signal handler  
   signal(SIGINT, signalHandler);  

   while(++i) {
      cout << "Going to sleep...." << endl;
      if( i == 3 ) {
         raise( SIGINT);
      }
      sleep(1);
   }

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau và sẽ tự động xuất hiện:

Going to sleep....
Going to sleep....
Going to sleep....
Interrupt signal (2) received.

Đa luồng là một dạng đa nhiệm chuyên biệt và đa nhiệm là tính năng cho phép máy tính của bạn chạy đồng thời hai hoặc nhiều chương trình. Nói chung, có hai loại đa nhiệm: dựa trên quy trình và dựa trên luồng.

Đa nhiệm dựa trên quy trình xử lý việc thực thi đồng thời các chương trình. Đa nhiệm dựa trên luồng xử lý việc thực thi đồng thời các phần của cùng một chương trình.

Một chương trình đa luồng chứa hai hoặc nhiều phần có thể chạy đồng thời. Mỗi phần của chương trình như vậy được gọi là một luồng và mỗi luồng xác định một đường dẫn thực thi riêng.

C ++ không chứa bất kỳ hỗ trợ tích hợp nào cho các ứng dụng đa luồng. Thay vào đó, nó hoàn toàn dựa vào hệ điều hành để cung cấp tính năng này.

Hướng dẫn này giả định rằng bạn đang làm việc trên Hệ điều hành Linux và chúng ta sẽ viết chương trình C ++ đa luồng bằng POSIX. POSIX Threads, hoặc Pthreads cung cấp API có sẵn trên nhiều hệ thống POSIX giống Unix như FreeBSD, NetBSD, GNU / Linux, Mac OS X và Solaris.

Tạo chủ đề

Quy trình sau đây được sử dụng để tạo một chuỗi POSIX:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)

Đây, pthread_createtạo một luồng mới và làm cho nó có thể thực thi được. Quy trình này có thể được gọi bất kỳ số lần nào từ bất kỳ đâu trong mã của bạn. Đây là mô tả của các tham số -

Sr.No Mô tả về Thông Số
1

thread

Một mã định danh không rõ ràng, duy nhất cho luồng mới được chương trình con trả về.

2

attr

Một đối tượng thuộc tính không rõ ràng có thể được sử dụng để đặt thuộc tính chuỗi. Bạn có thể chỉ định một đối tượng thuộc tính luồng hoặc NULL cho các giá trị mặc định.

3

start_routine

Quy trình C ++ mà luồng sẽ thực thi khi nó được tạo.

4

arg

Một đối số duy nhất có thể được chuyển đến start_routine. Nó phải được truyền bằng tham chiếu như một kiểu con trỏ kiểu void. NULL có thể được sử dụng nếu không có đối số nào được chuyển.

Số luồng tối đa có thể được tạo bởi một quy trình phụ thuộc vào việc triển khai. Sau khi được tạo, các luồng là đồng đẳng và có thể tạo ra các luồng khác. Không có hệ thống phân cấp hoặc sự phụ thuộc ngụ ý giữa các luồng.

Chấm dứt chủ đề

Có một quy trình sau đây mà chúng tôi sử dụng để kết thúc một chuỗi POSIX:

#include <pthread.h>
pthread_exit (status)

Đây pthread_exitđược sử dụng để thoát khỏi một chủ đề một cách rõ ràng. Thông thường, quy trình pthread_exit () được gọi sau khi một luồng đã hoàn thành công việc của nó và không còn bắt buộc phải tồn tại.

Nếu main () kết thúc trước khi luồng nó đã tạo và thoát bằng pthread_exit (), các luồng khác sẽ tiếp tục thực thi. Nếu không, chúng sẽ tự động kết thúc khi main () kết thúc.

Example

Mã ví dụ đơn giản này tạo 5 luồng với quy trình pthread_create (). Mỗi chuỗi in một "Hello World!" và sau đó kết thúc bằng lệnh gọi đến pthread_exit ().

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   
   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Biên dịch chương trình sau bằng thư viện -lpthread như sau:

$gcc test.cpp -lpthread

Bây giờ, hãy thực thi chương trình của bạn để đưa ra kết quả sau:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4

Chuyển đối số thành chủ đề

Ví dụ này cho thấy cách chuyển nhiều đối số qua một cấu trúc. Bạn có thể chuyển bất kỳ kiểu dữ liệu nào trong một chuỗi gọi lại vì nó trỏ đến void như được giải thích trong ví dụ sau:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

struct thread_data {
   int  thread_id;
   char *message;
};

void *PrintHello(void *threadarg) {
   struct thread_data *my_data;
   my_data = (struct thread_data *) threadarg;

   cout << "Thread ID : " << my_data->thread_id ;
   cout << " Message : " << my_data->message << endl;

   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   struct thread_data td[NUM_THREADS];
   int rc;
   int i;

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout <<"main() : creating thread, " << i << endl;
      td[i].thread_id = i;
      td[i].message = "This is message";
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message

Tham gia và tách chuỗi

Có hai quy trình sau đây mà chúng ta có thể sử dụng để tham gia hoặc tách các chuỗi -

pthread_join (threadid, status) 
pthread_detach (threadid)

Chương trình con pthread_join () chặn luồng đang gọi cho đến khi luồng 'threadid' được chỉ định kết thúc. Khi một luồng được tạo, một trong các thuộc tính của nó xác định liệu nó có thể nối hay tách rời. Chỉ các chủ đề được tạo dưới dạng có thể nối mới có thể được tham gia. Nếu một chuỗi được tạo ra dưới dạng tách rời, nó không bao giờ có thể được tham gia.

Ví dụ này trình bày cách chờ hoàn thành luồng bằng cách sử dụng quy trình tham gia Pthread.

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define NUM_THREADS 5

void *wait(void *t) {
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}

int main () {
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;

   // Initialize and set thread joinable
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], &attr, wait, (void *)i );

      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // free attribute and wait for the other threads
   pthread_attr_destroy(&attr);
   for( i = 0; i < NUM_THREADS; i++ ) {
      rc = pthread_join(threads[i], &status);
      if (rc) {
         cout << "Error:unable to join," << rc << endl;
         exit(-1);
      }
      
      cout << "Main: completed thread id :" << i ;
      cout << "  exiting with status :" << status << endl;
   }

   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0  exiting with status :0
Main: completed thread id :1  exiting with status :0
Main: completed thread id :2  exiting with status :0
Main: completed thread id :3  exiting with status :0
Main: completed thread id :4  exiting with status :0
Main: program exiting.

CGI là gì?

  • Giao diện Cổng chung, hoặc CGI, là một tập hợp các tiêu chuẩn xác định cách thông tin được trao đổi giữa máy chủ web và tập lệnh tùy chỉnh.

  • Các thông số kỹ thuật CGI hiện được duy trì bởi NCSA và NCSA định nghĩa CGI như sau:

  • Giao diện cổng chung, hoặc CGI, là một tiêu chuẩn cho các chương trình cổng bên ngoài để giao tiếp với các máy chủ thông tin như máy chủ HTTP.

  • Phiên bản hiện tại là CGI / 1.1 và CGI / 1.2 đang được hoàn thiện.

Duyệt web

Để hiểu khái niệm về CGI, hãy xem điều gì sẽ xảy ra khi chúng ta nhấp vào siêu liên kết để duyệt một trang web hoặc URL cụ thể.

  • Trình duyệt của bạn liên hệ với máy chủ web HTTP và yêu cầu URL. tên tệp.

  • Máy chủ Web sẽ phân tích cú pháp URL và sẽ tìm kiếm tên tệp. Nếu nó tìm thấy tệp được yêu cầu thì máy chủ web sẽ gửi tệp đó trở lại trình duyệt, nếu không sẽ gửi thông báo lỗi cho biết rằng bạn đã yêu cầu tệp sai.

  • Trình duyệt web nhận phản hồi từ máy chủ web và hiển thị tệp đã nhận hoặc thông báo lỗi dựa trên phản hồi nhận được.

Tuy nhiên, có thể thiết lập máy chủ HTTP theo cách mà bất cứ khi nào một tệp trong một thư mục nhất định được yêu cầu, tệp đó sẽ không được gửi lại; thay vào đó, nó được thực thi như một chương trình và kết quả được tạo ra từ chương trình được gửi trở lại trình duyệt của bạn để hiển thị.

Giao diện cổng chung (CGI) là một giao thức chuẩn để cho phép các ứng dụng (được gọi là chương trình CGI hoặc tập lệnh CGI) tương tác với máy chủ Web và với máy khách. Các chương trình CGI này có thể được viết bằng Python, PERL, Shell, C hoặc C ++, v.v.

Sơ đồ kiến ​​trúc CGI

Chương trình đơn giản sau đây cho thấy một kiến ​​trúc đơn giản của CGI:

Cấu hình máy chủ web

Trước khi bạn tiếp tục Lập trình CGI, hãy đảm bảo rằng Máy chủ Web của bạn hỗ trợ CGI và nó được cấu hình để xử lý các Chương trình CGI. Tất cả các Chương trình CGI được thực thi bởi máy chủ HTTP được lưu giữ trong một thư mục được cấu hình trước. Thư mục này được gọi là thư mục CGI và theo quy ước, nó được đặt tên là / var / www / cgi-bin. Theo quy ước, các tệp CGI sẽ có phần mở rộng là.cgi, mặc dù chúng có thể thực thi C ++.

Theo mặc định, Apache Web Server được cấu hình để chạy các chương trình CGI trong / var / www / cgi-bin. Nếu bạn muốn chỉ định bất kỳ thư mục nào khác để chạy các tập lệnh CGI của mình, bạn có thể sửa đổi phần sau trong tệp httpd.conf -

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options ExecCGI
   Order allow,deny
   Allow from all
</Directory>
 
<Directory "/var/www/cgi-bin">
   Options All
</Directory>

Ở đây, tôi giả sử rằng bạn đã thiết lập và chạy Web Server thành công và bạn có thể chạy bất kỳ chương trình CGI nào khác như Perl hoặc Shell, v.v.

Chương trình CGI đầu tiên

Xem xét nội dung Chương trình C ++ sau:

#include <iostream>
using namespace std;

int main () {
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Hello World - First CGI Program</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<h2>Hello World! This is my first CGI program</h2>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Biên dịch mã trên và đặt tên tệp thực thi là cplusplus.cgi. Tệp này đang được lưu trong thư mục / var / www / cgi-bin và nó có nội dung như sau. Trước khi chạy chương trình CGI, hãy đảm bảo rằng bạn đã thay đổi chế độ tệp bằng cách sử dụngchmod 755 cplusplus.cgi Lệnh UNIX để thực thi tệp.

Chương trình CGI đầu tiên của tôi

Chương trình C ++ ở trên là một chương trình đơn giản đang ghi đầu ra của nó trên màn hình tức là tệp STDOUT. Có một tính năng quan trọng và bổ sung có sẵn đó là in dòng đầu tiênContent-type:text/html\r\n\r\n. Dòng này được gửi trở lại trình duyệt và chỉ định loại nội dung sẽ hiển thị trên màn hình trình duyệt. Bây giờ bạn chắc hẳn đã hiểu khái niệm cơ bản về CGI và bạn có thể viết nhiều chương trình CGI phức tạp bằng Python. Một chương trình C ++ CGI có thể tương tác với bất kỳ hệ thống bên ngoài nào khác, chẳng hạn như RDBMS, để trao đổi thông tin.

Tiêu đề HTTP

Dòng Content-type:text/html\r\n\r\nlà một phần của tiêu đề HTTP, được gửi đến trình duyệt để hiểu nội dung. Tất cả tiêu đề HTTP sẽ ở dạng sau:

HTTP Field Name: Field Content
 
For Example
Content-type: text/html\r\n\r\n

Có một số tiêu đề HTTP quan trọng khác mà bạn sẽ sử dụng thường xuyên trong Lập trình CGI của mình.

Sr.No Tiêu đề & Mô tả
1

Content-type:

Một chuỗi MIME xác định định dạng của tệp được trả về. Ví dụ là Content-type: text / html.

2

Expires: Date

Ngày thông tin trở nên không hợp lệ. Điều này sẽ được sử dụng bởi trình duyệt để quyết định khi nào một trang cần được làm mới. Chuỗi ngày hợp lệ phải có định dạng 01/01/1998 12:00:00 GMT.

3

Location: URL

URL sẽ được trả lại thay vì URL được yêu cầu. Bạn có thể sử dụng tệp này để chuyển hướng một yêu cầu đến bất kỳ tệp nào.

4

Last-modified: Date

Ngày sửa đổi cuối cùng của tài nguyên.

5

Content-length: N

Độ dài, tính bằng byte, của dữ liệu được trả về. Trình duyệt sử dụng giá trị này để báo cáo thời gian tải xuống ước tính cho một tệp.

6

Set-Cookie: String

Đặt cookie được chuyển qua chuỗi .

Biến môi trường CGI

Tất cả chương trình CGI sẽ có quyền truy cập vào các biến môi trường sau. Các biến này đóng một vai trò quan trọng trong khi viết bất kỳ chương trình CGI nào.

Sr.No Tên và mô tả biến
1

CONTENT_TYPE

Kiểu dữ liệu của nội dung, được sử dụng khi máy khách gửi nội dung đính kèm đến máy chủ. Ví dụ: tải lên tệp, v.v.

2

CONTENT_LENGTH

Độ dài của thông tin truy vấn chỉ có sẵn cho các yêu cầu ĐĂNG.

3

HTTP_COOKIE

Trả về các cookie đã đặt ở dạng cặp khóa & giá trị.

4

HTTP_USER_AGENT

Trường tiêu đề yêu cầu Tác nhân người dùng chứa thông tin về tác nhân người dùng khởi tạo yêu cầu. Nó là một tên của trình duyệt web.

5

PATH_INFO

Đường dẫn cho tập lệnh CGI.

6

QUERY_STRING

Thông tin mã hóa URL được gửi với yêu cầu phương thức GET.

7

REMOTE_ADDR

Địa chỉ IP của máy chủ từ xa thực hiện yêu cầu. Điều này có thể hữu ích cho việc ghi nhật ký hoặc cho mục đích xác thực.

số 8

REMOTE_HOST

Tên đầy đủ của máy chủ thực hiện yêu cầu. Nếu thông tin này không có sẵn thì REMOTE_ADDR có thể được sử dụng để lấy địa chỉ IR.

9

REQUEST_METHOD

Phương pháp được sử dụng để thực hiện yêu cầu. Các phương pháp phổ biến nhất là GET và POST.

10

SCRIPT_FILENAME

Đường dẫn đầy đủ đến tập lệnh CGI.

11

SCRIPT_NAME

Tên của tập lệnh CGI.

12

SERVER_NAME

Tên máy chủ hoặc Địa chỉ IP của máy chủ.

13

SERVER_SOFTWARE

Tên và phiên bản của phần mềm mà máy chủ đang chạy.

Đây là chương trình CGI nhỏ để liệt kê tất cả các biến CGI.

#include <iostream>
#include <stdlib.h>
using namespace std;

const string ENV[ 24 ] = {
   "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",   
   "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             
   "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",         
   "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            
   "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",      
   "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
   "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",      
   "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",     
   "SERVER_SIGNATURE","SERVER_SOFTWARE" };   

int main () {
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>CGI Environment Variables</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";

   for ( int i = 0; i < 24; i++ ) {
      cout << "<tr><td>" << ENV[ i ] << "</td><td>";
      
      // attempt to retrieve value of environment variable
      char *value = getenv( ENV[ i ].c_str() );  
      if ( value != 0 ) {
         cout << value;                                 
      } else {
         cout << "Environment variable does not exist.";
      }
      cout << "</td></tr>\n";
   }
   
   cout << "</table><\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Thư viện C ++ CGI

Đối với các ví dụ thực tế, bạn sẽ cần thực hiện nhiều thao tác bằng chương trình CGI của mình. Có một thư viện CGI được viết cho chương trình C ++ mà bạn có thể tải xuống từ ftp://ftp.gnu.org/gnu/cgicc/ và làm theo các bước để cài đặt thư viện -

$tar xzf cgicc-X.X.X.tar.gz 
$cd cgicc-X.X.X/ $./configure --prefix=/usr 
$make $make install

Bạn có thể kiểm tra tài liệu liên quan có sẵn tại 'Tài liệu C ++ CGI Lib .

Phương thức GET và POST

Chắc hẳn bạn đã gặp nhiều tình huống khi bạn cần chuyển một số thông tin từ trình duyệt đến máy chủ web và cuối cùng là Chương trình CGI của mình. Thông thường nhất, trình duyệt sử dụng hai phương pháp để chuyển thông tin này đến máy chủ web. Các phương thức này là GET Method và POST Method.

Truyền thông tin bằng phương pháp GET

Phương thức GET gửi thông tin người dùng đã mã hóa được thêm vào yêu cầu trang. Trang và thông tin được mã hóa được phân tách bằng dấu? nhân vật như sau -

http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2

Phương thức GET là phương thức mặc định để chuyển thông tin từ trình duyệt đến máy chủ web và nó tạo ra một chuỗi dài xuất hiện trong hộp Location: của trình duyệt của bạn. Không bao giờ sử dụng phương thức GET nếu bạn có mật khẩu hoặc thông tin nhạy cảm khác để chuyển đến máy chủ. Phương thức GET có giới hạn về kích thước và bạn có thể chuyển tối đa 1024 ký tự trong một chuỗi yêu cầu.

Khi sử dụng phương thức GET, thông tin được chuyển bằng tiêu đề QUERY_STRING http và sẽ có thể truy cập được trong Chương trình CGI của bạn thông qua biến môi trường QUERY_STRING.

Bạn có thể chuyển thông tin bằng cách chỉ cần nối các cặp khóa và giá trị cùng với bất kỳ URL nào hoặc bạn có thể sử dụng thẻ HTML <FORM> để chuyển thông tin bằng phương thức GET.

Ví dụ về URL đơn giản: Phương thức lấy

Đây là một URL đơn giản sẽ chuyển hai giá trị đến chương trình hello_get.py bằng phương thức GET.

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

Dưới đây là một chương trình để tạo cpp_get.cgiChương trình CGI để xử lý đầu vào do trình duyệt web cung cấp. Chúng tôi sẽ sử dụng thư viện C ++ CGI giúp dễ dàng truy cập thông tin đã chuyển -

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>  

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
   
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Using GET and POST Methods</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("first_name");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "First name: " << **fi << endl;  
   } else {
      cout << "No text entered for first name" << endl;  
   }
   
   cout << "<br/>\n";
   fi = formData.getElement("last_name");  
   if( !fi->isEmpty() &&fi != (*formData).end()) {  
      cout << "Last name: " << **fi << endl;  
   } else {
      cout << "No text entered for last name" << endl;  
   }
   
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Bây giờ, hãy biên dịch chương trình trên như sau:

$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc

Tạo cpp_get.cgi và đưa nó vào thư mục CGI của bạn và cố gắng truy cập bằng liên kết sau:

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

Điều này sẽ tạo ra kết quả sau:

First name: ZARA 
Last name: ALI

MẪU đơn giản Ví dụ: Phương pháp GET

Đây là một ví dụ đơn giản chuyển hai giá trị bằng HTML FORM và nút gửi. Chúng tôi sẽ sử dụng cùng một tập lệnh CGI cpp_get.cgi để xử lý đầu vào này.

<form action = "/cgi-bin/cpp_get.cgi" method = "get">
   First Name: <input type = "text" name = "first_name">  <br />
 
   Last Name: <input type = "text" name = "last_name" />
   <input type = "submit" value = "Submit" />
</form>

Đây là kết quả thực tế của biểu mẫu trên. Bạn điền Họ và Tên rồi bấm nút gửi để xem kết quả.

Truyền thông tin bằng phương pháp POST

Phương pháp truyền thông tin đến chương trình CGI thường đáng tin cậy hơn là phương pháp POST. Điều này đóng gói thông tin theo cách giống hệt như các phương thức GET, nhưng thay vì gửi nó dưới dạng một chuỗi văn bản sau dấu? trong URL, nó sẽ gửi nó dưới dạng một tin nhắn riêng biệt. Thông báo này đi vào tập lệnh CGI ở dạng đầu vào chuẩn.

Chương trình cpp_get.cgi tương tự cũng sẽ xử lý phương thức POST. Chúng ta hãy lấy ví dụ tương tự như trên, chuyển hai giá trị bằng HTML FORM và nút gửi nhưng lần này với phương thức POST như sau:

<form action = "/cgi-bin/cpp_get.cgi" method = "post">
   First Name: <input type = "text" name = "first_name"><br />
   Last Name: <input type = "text" name = "last_name" />
 
   <input type = "submit" value = "Submit" />
</form>

Đây là kết quả thực tế của biểu mẫu trên. Bạn điền Họ và Tên rồi bấm nút gửi để xem kết quả.

Chuyển dữ liệu hộp kiểm sang chương trình CGI

Hộp kiểm được sử dụng khi bắt buộc phải chọn nhiều tùy chọn.

Đây là mã HTML mẫu cho biểu mẫu có hai hộp kiểm -

<form action = "/cgi-bin/cpp_checkbox.cgi" method = "POST" target = "_blank">
   <input type = "checkbox" name = "maths" value = "on" /> Maths
   <input type = "checkbox" name = "physics" value = "on" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

Kết quả của mã này là dạng sau:

Dưới đây là chương trình C ++, sẽ tạo ra tập lệnh cpp_checkbox.cgi để xử lý đầu vào do trình duyệt web cung cấp thông qua nút hộp kiểm.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
   bool maths_flag, physics_flag;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Checkbox Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   maths_flag = formData.queryCheckbox("maths");
   if( maths_flag ) {  
      cout << "Maths Flag: ON " << endl;  
   } else {
      cout << "Maths Flag: OFF " << endl;  
   }
   cout << "<br/>\n";

   physics_flag = formData.queryCheckbox("physics");
   if( physics_flag ) {  
      cout << "Physics Flag: ON " << endl;  
   } else {
      cout << "Physics Flag: OFF " << endl;  
   }
   
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Truyền dữ liệu nút radio sang chương trình CGI

Các nút Radio được sử dụng khi chỉ cần chọn một tùy chọn.

Đây là mã HTML mẫu cho biểu mẫu có hai nút radio -

<form action = "/cgi-bin/cpp_radiobutton.cgi" method = "post" target = "_blank">
   <input type = "radio" name = "subject" value = "maths" checked = "checked"/> Maths 
   <input type = "radio" name = "subject" value = "physics" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

Kết quả của mã này là dạng sau:

Dưới đây là chương trình C ++, sẽ tạo ra tập lệnh cpp_radiobutton.cgi để xử lý đầu vào do trình duyệt web cung cấp thông qua các nút radio.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Radio Button Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("subject");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Radio box selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Chuyển dữ liệu vùng văn bản sang chương trình CGI

Phần tử TEXTAREA được sử dụng khi văn bản nhiều dòng phải được chuyển đến Chương trình CGI.

Đây là mã HTML mẫu cho biểu mẫu có hộp TEXTAREA -

<form action = "/cgi-bin/cpp_textarea.cgi" method = "post" target = "_blank">
   <textarea name = "textcontent" cols = "40" rows = "4">
      Type your text here...
   </textarea>
   <input type = "submit" value = "Submit" />
</form>

Kết quả của mã này là dạng sau:

Dưới đây là chương trình C ++, sẽ tạo ra tập lệnh cpp_textarea.cgi để xử lý đầu vào do trình duyệt web cung cấp thông qua vùng văn bản.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Text Area Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("textcontent");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Text Content: " << **fi << endl;  
   } else {
      cout << "No text entered" << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Chuyển dữ liệu hộp thả xuống cho chương trình CGI

Hộp thả xuống được sử dụng khi chúng ta có nhiều tùy chọn nhưng chỉ một hoặc hai tùy chọn được chọn.

Đây là mã HTML mẫu cho biểu mẫu có một hộp thả xuống -

<form action = "/cgi-bin/cpp_dropdown.cgi" method = "post" target = "_blank">
   <select name = "dropdown">
      <option value = "Maths" selected>Maths</option>
      <option value = "Physics">Physics</option>
   </select>
   
   <input type = "submit" value = "Submit"/>
</form>

Kết quả của mã này là dạng sau:

Dưới đây là chương trình C ++, sẽ tạo ra tập lệnh cpp_dropdown.cgi để xử lý đầu vào do trình duyệt web cung cấp thông qua hộp thả xuống.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main () {
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Drop Down Box Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("dropdown");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Value Selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Sử dụng Cookie trong CGI

Giao thức HTTP là một giao thức không trạng thái. Nhưng đối với một trang web thương mại, cần phải duy trì thông tin phiên giữa các trang khác nhau. Ví dụ: một đăng ký người dùng kết thúc sau khi hoàn thành nhiều trang. Nhưng làm thế nào để duy trì thông tin phiên của người dùng trên tất cả các trang web.

Trong nhiều tình huống, sử dụng cookie là phương pháp hiệu quả nhất để ghi nhớ và theo dõi các sở thích, mua hàng, hoa hồng và các thông tin khác cần thiết để có trải nghiệm khách truy cập hoặc thống kê trang web tốt hơn.

Làm thế nào nó hoạt động

Máy chủ của bạn gửi một số dữ liệu đến trình duyệt của khách truy cập dưới dạng cookie. Trình duyệt có thể chấp nhận cookie. Nếu có, nó được lưu trữ dưới dạng bản ghi văn bản thuần túy trên ổ cứng của khách truy cập. Bây giờ, khi khách truy cập đến một trang khác trên trang web của bạn, cookie sẽ có sẵn để truy xuất. Sau khi được truy xuất, máy chủ của bạn biết / ghi nhớ những gì đã được lưu trữ.

Cookie là một bản ghi dữ liệu văn bản thuần túy gồm 5 trường có độ dài thay đổi -

  • Expires- Điều này hiển thị ngày cookie sẽ hết hạn. Nếu ô này trống, cookie sẽ hết hạn khi khách truy cập thoát khỏi trình duyệt.

  • Domain - Điều này hiển thị tên miền của trang web của bạn.

  • Path- Điều này hiển thị đường dẫn đến thư mục hoặc trang web đặt cookie. Phần này có thể để trống nếu bạn muốn lấy cookie từ bất kỳ thư mục hoặc trang nào.

  • Secure- Nếu trường này chứa từ "an toàn" thì cookie chỉ có thể được truy xuất bằng máy chủ bảo mật. Nếu trường này trống, không có hạn chế như vậy tồn tại.

  • Name = Value - Cookie được thiết lập và truy xuất dưới dạng các cặp khóa và giá trị.

Thiết lập Cookie

Rất dễ dàng để gửi cookie đến trình duyệt. Các cookie này sẽ được gửi cùng với Tiêu đề HTTP trước khi Loại nội dung được gửi. Giả sử bạn muốn đặt UserID và Mật khẩu làm cookie. Vì vậy, cài đặt cookie sẽ được thực hiện như sau

#include <iostream>
using namespace std;

int main () {
   cout << "Set-Cookie:UserID = XYZ;\r\n";
   cout << "Set-Cookie:Password = XYZ123;\r\n";
   cout << "Set-Cookie:Domain = www.tutorialspoint.com;\r\n";
   cout << "Set-Cookie:Path = /perl;\n";
   cout << "Content-type:text/html\r\n\r\n";

   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   cout << "Setting cookies" << endl;  
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Từ ví dụ này, bạn chắc hẳn đã hiểu cách đặt cookie. Chúng tôi sử dụngSet-Cookie Tiêu đề HTTP để đặt cookie.

Tại đây, bạn có thể tùy chọn đặt các thuộc tính cookie như Expires, Domain và Path. Đáng chú ý là cookie được đặt trước khi gửi dòng ma thuật"Content-type:text/html\r\n\r\n.

Biên dịch chương trình trên để tạo setcookies.cgi và cố gắng thiết lập cookie bằng liên kết sau. Nó sẽ đặt bốn cookie trên máy tính của bạn -

/cgi-bin/setcookies.cgi

Truy xuất Cookie

Thật dễ dàng để truy xuất tất cả các cookie đã đặt. Cookie được lưu trữ trong biến môi trường CGI HTTP_COOKIE và chúng sẽ có dạng sau.

key1 = value1; key2 = value2; key3 = value3....

Đây là một ví dụ về cách lấy cookie.

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main () {
   Cgicc cgi;
   const_cookie_iterator cci;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";
   
   // get environment variables
   const CgiEnvironment& env = cgi.getEnvironment();

   for( cci = env.getCookieList().begin();
   cci != env.getCookieList().end(); 
   ++cci ) {
      cout << "<tr><td>" << cci->getName() << "</td><td>";
      cout << cci->getValue();                                 
      cout << "</td></tr>\n";
   }
   
   cout << "</table><\n";
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Bây giờ, hãy biên dịch chương trình trên để tạo getcookies.cgi và cố gắng lấy danh sách tất cả các cookie có sẵn trong máy tính của bạn -

/cgi-bin/getcookies.cgi

Thao tác này sẽ tạo ra danh sách tất cả bốn cookie được đặt trong phần trước và tất cả các cookie khác được đặt trong máy tính của bạn -

UserID XYZ 
Password XYZ123 
Domain www.tutorialspoint.com 
Path /perl

Ví dụ về Tải lên Tệp

Để tải tệp lên, biểu mẫu HTML phải có thuộc tính enctype được đặt thành multipart/form-data. Thẻ đầu vào với loại tệp sẽ tạo nút "Duyệt qua".

<html>
   <body>
      <form enctype = "multipart/form-data" action = "/cgi-bin/cpp_uploadfile.cgi"
         method = "post">
         <p>File: <input type = "file" name = "userfile" /></p>
         <p><input type = "submit" value = "Upload" /></p>
      </form>
   </body>
</html>

Kết quả của mã này là dạng sau:

Note- Ví dụ trên đã bị vô hiệu hóa có chủ ý để ngăn mọi người tải tệp lên máy chủ của chúng tôi. Nhưng bạn có thể thử mã trên với máy chủ của mình.

Đây là kịch bản cpp_uploadfile.cpp để xử lý tải lên tệp -

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main () {
   Cgicc cgi;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>File Upload in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   // get list of files to be uploaded
   const_file_iterator file = cgi.getFile("userfile");
   if(file != cgi.getFiles().end()) {
      // send data type at cout.
      cout << HTTPContentHeader(file->getDataType());
      // write content at cout.
      file->writeToStream(cout);
   }
   cout << "<File uploaded successfully>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Ví dụ trên là để viết nội dung tại cout nhưng bạn có thể mở luồng tệp của mình và lưu nội dung của tệp đã tải lên trong tệp ở vị trí mong muốn.

Hy vọng bạn đã thích hướng dẫn này. Nếu có, vui lòng gửi cho chúng tôi phản hồi của bạn.