C++: تمرين: قاعدة بيانات بسيطة
آخر تحديث: 2026-08-26
في الدرس 51، بنينا نظام دفتر عناوين.
الآن، سنبني ثاني مشروع تطبيقي شامل — قاعدة بيانات بسيطة.
هذا المشروع يستخدم العديد من ميزات C++ المتقدمة، مما يجعله اختبارًا رائعًا لما تعلمته.
1. متطلبات المشروع
(1) 1.1 المتطلبات الوظيفية
| الميزة | الوصف |
|---|---|
| CREATE TABLE | إنشاء جدول |
| INSERT | إدخال بيانات |
| SELECT | استعلام بيانات |
| WHERE | تصفية شرطية |
| فهرس | تسريع الاستعلامات |
| معاملة | ضمان ACID |
(2) 1.2 تصميم مبسط
بما أن هذا مشروع تعليمي، سنصنع نسخة مبسطة:
- دعم نوعي
intوstringفقط - دعم استعلامات جدول واحد فقط
- الفهارس مُنفذة بـ
std::map - البيانات مخزنة في الذاكرة (ثبات اختياري)
2. تصميم بنية الجدول
(1) 2.1 تعريف العمود
▶ مثال 2: مثال على الكود (الصعوبة ⭐)
#include <iostream>
#include <string>
#include <variant>
#include <vector>
// تعريف العمود
struct Column {
std::string name;
enum Type { INT, STRING } type;
};
// نوع القيمة (استخدم variant لتخزين أنواع مختلفة)
using Value = std::variant<int, std::string>;
// صف (صف واحد من البيانات)
using Row = std::vector<Value>;
// جدول
class Table {
private:
std::string name;
std::vector<Column> columns;
std::vector<Row> rows;
public:
Table(const std::string& name, const std::vector<Column>& columns)
: name(name), columns(columns) {}
// إدراج صف
void insert(const Row& row) {
if (row.size() != columns.size()) {
std::cerr << "Column count mismatch" << std::endl;
return;
}
rows.push_back(row);
}
// استعلام (مبسط: إرجاع جميع الصفوف)
std::vector<Row> select() {
return rows;
}
// عرض بنية الجدول
void describe() const {
std::cout << "Table name: " << name << std::endl;
std::cout << "Columns: " << std::endl;
for (const auto& col : columns) {
std::cout << " " << col.name << " (";
if (col.type == Column::INT) {
std::cout << "INT";
} else {
std::cout << "STRING";
}
std::cout << ")" << std::endl;
}
}
};
الخرج:
Table name:
Columns:
(
INT
STRING
)
3. تنفيذ الاستعلام
(1) 3.1 عبارة WHERE
// دالة المسند (لـ WHERE)
using Predicate = std::function<bool(const Row&)>;
// استعلام بشرط
std::vector<Row> selectWhere(Predicate pred) {
std::vector<Row> result;
for (const auto& row : rows) {
if (pred(row)) {
result.push_back(row);
}
}
return result;
}
// مثال: إيجاد صفوف حيث العمر > 18
auto predicate = [](const Row& row) {
int age = std::get<int>(row[1]); // افترض أن العمود 2 هو العمر
return age > 18;
};
auto result = table.selectWhere(predicate);
4. تنفيذ الفهرس
(1) 4.1 فهرس بسيط
#include <map>
// فهرس (مبسط: فهرسة أنواع int فقط)
class Index {
private:
std::map<int, std::vector<int>> index; // القيمة → قائمة أرقام الصفوف
public:
void build(const std::vector<Row>& rows, int colIndex) {
index.clear();
for (int i = 0; i < rows.size(); i++) {
int key = std::get<int>(rows[i][colIndex]);
index[key].push_back(i);
}
}
std::vector<int> lookup(int key) {
auto it = index.find(key);
if (it != index.end()) {
return it->second;
}
return {};
}
};
5. دعم المعاملات
(1) 5.1 معاملة مبسطة
#include <stack>
class Transaction {
private:
std::stack<std::vector<Row>> undoStack;
public:
// بدء المعاملة (حفظ الحالة الحالية)
void begin(Table& table) {
undoStack.push(table.rows);
}
// تأكيد (تفريغ مكاكب التراجع)
void commit() {
while (!undoStack.empty()) {
undoStack.pop();
}
}
// تراجع (استعادة الحالة السابقة)
void rollback(Table& table) {
if (!undoStack.empty()) {
table.rows = undoStack.top();
undoStack.pop();
}
}
};
6. مثال كامل
▶ مثال 1: استخدام قاعدة البيانات البسيطة (الصعوبة ⭐⭐⭐)
int main() {
// إنشاء جدول
Table t("users", {{"name", Column::STRING}, {"age", Column::INT}});
// إدخال بيانات
t.insert({"Alice", 25});
t.insert({"Bob", 30});
t.insert({"Charlie", 20});
// استعلام الكل
auto rows = t.select();
std::cout << "All users:" << std::endl;
for (const auto& row : rows) {
std::cout << std::get<std::string>(row[0]) << ", "
<< std::get<int>(row[1]) << std::endl;
}
return 0;
}
الخرج:
All users:
,
7. اتجاهات التوسيع
(1) 7.1 توسيعات الميزات
| الميزة | الصعوبة | الوصف |
|---|---|---|
| الثبات | ⭐⭐ | حفظ في ملف |
| JOIN | ⭐⭐⭐⭐ | ربط جداول متعددة |
| محلل SQL | ⭐⭐⭐⭐⭐ | تحليل عبارات SQL |
| التحكم في التزامن | ⭐⭐⭐⭐ | أمان الخيوط |
❓ تمارين
(1) تمرين أساسي (الصعوبة ⭐⭐)
أضف ميزة DELETE لقاعدة البيانات.
(2) تمرين متوسط (الصعوبة ⭐⭐⭐)
أضف ميزة UPDATE لقاعدة البيانات.
(3) تمرين متقدم (الصعوبة ⭐⭐⭐⭐)
نفذ محلل SQL بسيط يدعم SELECT * FROM table WHERE age > 18.
▶ مثال 3: تعريف بنية جدول قاعدة بيانات (الصعوبة ⭐)
#include <iostream>
#include <string>
#include <vector>
#include <variant>
// نوع القيمة (يدعم أنواع بيانات متعددة)
using Value = std::variant<int, std::string, double>;
// صف واحد من البيانات
struct Row {
int id;
Value name;
Value age;
Value score;
void display() const {
std::cout << "ID: " << id << std::endl;
std::cout << "Name: " << std::get<std::string>(name) << std::endl;
std::cout << "Age: " << std::get<int>(age) << std::endl;
std::cout << "Score: " << std::get<double>(score) << std::endl;
}
};
int main() {
Row r = {1, std::string("Alice"), 20, 95.5};
r.display();
return 0;
}
الخرج:
ID:
Name:
Age:
Score:
❓ أسئلة شائعة
📖 ملخص
| نقطة المعرفة | التطبيق |
|---|---|
| variant | تخزين قيم أنواع مختلفة |
vector<Row> |
تخزين بيانات الجدول |
| map | تنفيذ الفهارس |
| كائنات الدوال | تنفيذ مسندات WHERE |
- قاعدة بيانات بسيطة: بيانات في الذاكرة + ثبات في ملفات
- استخدام map للبحث بالمفتاح بـ O(log n)
- دعم واجهة أوامر CRUD
- تنسيق CSV أو JSON لتخزين البيانات
- معالجة الاستثناءات لاستقرار البرنامج
📝 تمارين
-
أساسي (الصعوبة ⭐): شغّل برنامج قاعدة البيانات، أنشئ جدول "طلاب" (حقول: رقم الطالب، الاسم، العمر، الدرجة)، أدرج 3 سجلات، واستعلم عن جميع السجلات.
-
متوسط (الصعوبة ⭐⭐): أضف ميزة "استعلام مرتب" — ادعم
SELECT * FROM table ORDER BY age. تلميح: استخدمstd::sort+ تعبير لامدا للترتيب حسب حقل محدد. -
متقدم (الصعوبة ⭐⭐⭐): نفذ "ربط جداول متعددة" — أنشئ جدولين (طلاب، درجات)، ادعم
SELECT students.name, grades.score FROM students JOIN grades ON students.id = grades.student_id. تحتاج لتصميم منطق JOIN ودمج النتائج.
الدرس التالي: ملخص الدورة وخارطة طريق التقدم (#53)