مثال بسيط
يحتوي المثال التالي على شيفرة يُراد تقسيمها إلى عدّة ملفّات مصدرية، سننظر الآن في كل ملف على حدة:
الملفات المصدرية
- my_function.h
في هذا الملف، لاحظ أن الترويسة التالية تحتوي على تصريح للدالة فقط، ولا تعرِّف دوال الترويسة تطبيقات للتصريحات إلا إن وجب معالجة الشيفرة أكثر أثناء التصريف، كما هو الحال في القوالب. وعادة ما تحتوي ملفات الترويسة على واقيات معالج مسبق (Preprocessor Guards) حتى لا تضاف نفس الترويسة مرتين. ويُنفَّذ الواقي بالتحقق من كون المفتاح الرمزي (Token) الفريد للمعالج المسبق معرَّفًا أم لا، ولا تُضمَّن الترويسة إلا إن كانت غير مضمَّنة من قبل. سيتم التعرف على كل من global_value
و ()my_function
على أنهما نفس البُنية إن أضيفت هذه الترويسة من قبَل عدة ملفات.
// my_function.h #ifndef MY_FUNCTION_H #define MY_FUNCTION_H const int global_value = 42; int my_function(); #endif // MY_FUNCTION_H
- my_function.cpp
في هذا الملف، لاحظ أن الملف المصدري المقابل للترويسة يدرِج الواجهة المعرَّفة في الترويسة، كي ينتبه المصرِّف إلى ما ينفذه الملف المصدري. ويتطلب الملف المصدري في هذا الحالة معرفة الثابت العام global_value
المعرَّف في ملف my_function.h
الذي استعرضناه قبل قليل، ولن يصرَّف هذا الملف المصدري بدون الترويسة.
// my_function.cpp #include "my_function.h" // or #include "my_function.hpp" int my_function() { return global_value; // 42; }
- main.cpp
تُدرج ملفّات الترويسة بعد ذلك في الملفّات المصدرية الأخرى التي ترغب في استخدام الوظائف المُعرّفة في واجهة الترويسة، دون الحاجة إلى معرفة تفاصيل تنفيذها، مما يساعد على اختزال الشيفرة. يستخدم البرنامج التالي الترويسة my_function.h
:
// main.cpp #include <iostream> // ترويسة مكتبة قياسية #include "my_function.h" // ترويسة خاصة int main(int argc, char** argv) { std::cout << my_function() << std::endl; return 0; }
عملية التصريف (The Compilation Process)
تكون ملفّات الترويسة غالبًا جزءًا من عملية التصريف، لذا يحدث ما يلي خلال عملية التصريف في العادةً:
على افتراض أنّ ملفّ الترويسة وملفّّ الشيفرة المصدرية موجودان في نفس المجلّد، فيمكن تصريف البرنامج عبر تنفيذ الأوامر التالية:
g++ - c my_function.cpp g++main.cpp my_function.o
السطر الأولُ في الشيفرة السابقة يصرِّف الملفَّ المصدري my_function.cpp
إلى my_function.o
، ويربط السطر الثاني ملفَّ الكائن الذي يتحوي تنفيذ ()int my_function
إلى نسخة الكائن المصرَّفة من main.cpp
ثم ينتج النسخة التنفيذية النهائية a.out
.
بالمقابل، إذا رغبت في تصريف main.cpp
إلى ملفّ كائنٍ أولًا، ثم ربط ملفّات التعليمات المصرّفة في النهاية، فيمكنك ذلك عبر الشيفرة التالية:
g++ -c my_function.cpp g++ -c main.cpp g++ main.o my_function.o
القوالب في ملفات الترويسات
تتطلّب القوالب إنشاء الشيفرة وقت التصريف: على سبيل المثال، تُحوّل دالّة مُقولَبة (templated function) إلى عدة دوالّ مختلفة بمجرد جعل الدالّة المُقَولبة معامِلًا (parameter) عبر استخدامها في الشيفرة المصدرية.
هذا يعني أنّه لا يمكن تفويض الدوالّ والتوابع وتعريفات الأصناف في القوالب إلى ملفّ مصدري آخر، ذلك أنّ أيّ شيفرة تستخدم بنية مُقولَبَة تحتاج إلى أن تَطَّلِع على تعريف تلك البنية لإنشاء الشيفرة المشتقّة. وعليه يجب أن تحتوي الشيفرة المُقولبَة على تعريفها في حال وُضِعت في الترويسات. هذا مثال على ذلك:
// templated_function.h template < typename T > T* null_T_pointer() { T* type_point = NULL; // وما بعدها C++11 في NULL بدلا من nullptr أو return type_point; }
معالجة التاريخ والوقت باستخدام الترويسة <chrono>
قياس الوقت باستخدام <chrono>
يمكن استخدام system_clock
لقيَاس الوقت المنقضي منذ مرحلة معيّنة من تنفيذ البرنامج.
الإصدار = C++ 11
#include <iostream> #include <chrono> #include <thread> int main() { auto start = std::chrono::system_clock::now(); { // الشيفرة المراد اختبارها std::this_thread::sleep_for(std::chrono::seconds(2)); } auto end = std::chrono::system_clock::now(); std::chrono::duration < double > elapsed = end - start; std::cout << "Elapsed time: " << elapsed.count() << "s"; }
استخدمنا في هذا المثال sleep_for
لجعل الخيط النشط ينام (sleep) لفترة زمنية مُقاسة بالثواني std::chrono::seconds
.
حساب عدد الأيام بين تاريخين
يوضّح هذا المثال كيفية حساب عدد الأيّام بين تاريخين، ويُحدَّد التاريخ بالصيغة سنة/شهر/يوم (year/month/day)، بالإضافة إلى ساعة/دقيقة/ثانية (hour/minute/second).
يحسب البرنامج التالي المستوحى من موقع cppreference عدد الأيام منذ عام 2000. سننشئ بُنية std::tm
من التاريخ الخام على النحو التالي:
-
year
يجب أن تكون 1900 أو أكبر. -
month
من يناير (1 - 12). -
day
اليوم من الشهر (1 - 31). -
minutes
الدقائق بعد الساعة (0 - 59). -
seconds
الثواني بعد الدقيقة (0 - 61)، و (0 - 60) منذ C++ 11.
#include <iostream> #include <string> #include <chrono> #include <ctime> std::tm CreateTmStruct(int year, int month, int day, int hour, int minutes, int seconds) { struct tm tm_ret = { 0 }; tm_ret.tm_sec = seconds; tm_ret.tm_min = minutes; tm_ret.tm_hour = hour; tm_ret.tm_mday = day; tm_ret.tm_mon = month - 1; tm_ret.tm_year = year - 1900; return tm_ret; } int get_days_in_year(int year) { using namespace std; using namespace std::chrono; // نريد أن تكون النتيجة بالأيام typedef duration < int, ratio_multiply < hours::period, ratio < 24 > > ::type > days; // بداية الوقت std::tm tm_start = CreateTmStruct(year, 1, 1, 0, 0, 0); auto tms = system_clock::from_time_t(std::mktime( & tm_start)); // نهاية الوقت std::tm tm_end = CreateTmStruct(year + 1, 1, 1, 0, 0, 0); auto tme = system_clock::from_time_t(std::mktime( & tm_end)); // حساب الوقت الذي مرّ بين التاريخين auto diff_in_days = std::chrono::duration_cast < days > (tme - tms); return diff_in_days.count(); } int main() { for (int year = 2000; year <= 2016; ++year) std::cout << "There are " << get_days_in_year(year) << " days in " << year << "\n"; }
هذا الدرس جزء من سلسلة دروس عن C++.
ترجمة -بتصرّف- للفصل Chapter 45: Header Files والفصل Chapter 66: Date and time using
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.