اذهب إلى المحتوى

السؤال

نشر

أحاول أن أقوم بعمل ملفين header وأحد هذه الملفات معتمد على الآخر:
الملف الأول square.h:
 

int getSquareSides()
{
    return 4;	// مجرد كود بسيط
}

الملف الثاني geometry.h يعتمد على الملف الأول ويقوم بتضمينه كالتالي:
 

#include "square.h"

ملف main.cpp:

#include "square.h"
#include "geometry.h"

int main()
{
	// ...
    return 0;
}

عندما أقوم بتضمين كلا الملفين يظهر لي الخطأ التالي في ملف square.h:

Error	C2084	function 'int getSquareSides(void)' already has a body	

ما سبب هذا الخطأ؟ وكيف أقوم بتضمين ملف ترويسة header أكثر من مرة بدون ظهور هذا الخطأ؟

Recommended Posts

  • 2
نشر

يظهر هذا الخطأ بسبب تعريف الدالة getSquareSides أكثر من مرة (مرة لكل تضمين include) وبالتالي لا يستطيع المترجم التفريق بين الدوال التي لها نفس التوقيع signature (نوع الرجوع return type + اسم الدالة + المعاملات التي تقبلها الدالة)، وهنا ما يقوم به المصرف compiler بشكل مفصل:
أولًا يقوم المصرف بتضمين الملف square.h في الملف main.cpp، وبالتالي يتم نسخ الدالة getSquareSides إلى الملف main.cpp لأول مرة

بعد ذلك يتم تضمين الملف geometry.h في الملف main.cpp، والذي بدورة يقوم بتضمين الملف square.h مرة أخرى، وبهذا يتم نسخ محتوى الملف square.h إلى داخل geometry.h ثم نسخ محتوى الملف geometry.h (بما في ذلك الدالة getSquareSides) إلى الملف main.cpp

وسيكون شكل الكود في النهاية (بالنسبة للمصرف compiler)، كالتالي:
 

int getSquareSides()  // من الملف square.h
{
    return 4;
}

int getSquareSides() // من الملف geometry.h (عبر square.h)
{
    return 4;
}

int main()
{
    return 0;
}

كل ملف على حدى لا يحتوي على أخطاء ولكن إستدعاء هذه الملفات بشكل هرمي ومتوازي معًا يسبب خطأ تعريف نفس الدالة لأكثر من مرة.

لحل هذه المشكلة يجب إستخدام Header guards أو ما يسمى بواقيات معالج مسبق (Preprocessor Guards)، كالتالي:

الملف square.h:

#ifndef SQUARE_H
#define SQUARE_H
// لن يتم تضمين الدالة التالية إلا مرة واحدة فقط
int getSquareSides()
{
    return 4;
}

#endif

الملف geometry.h:

#ifndef GEOMETRY_H
#define GEOMETRY_H

#include "square.h"

#endif

ويبقى الملف main.cpp كما هو بدون تغير، وبالتالي سيكون شكل الملف main.cpp بعد عملية preprocessing على الشكل التالي:

// تضمين الملف square.h من داخل main.cpp
#ifndef SQUARE_H
#define SQUARE_H

int getSquareSides()
{
    return 4;
}

#endif // SQUARE_H

// تضمين الملف geometry.h من داخل main.cpp
#ifndef GEOMETRY_H
#define GEOMETRY_H
#ifndef SQUARE_H // تضمين الملف square.h من داخل geometry.cpp , SQUARE_H معرفة بالفعل في الأعلى
#define SQUARE_H // لذلك لن يتم تضمين هذا المحتوى مرة أخرى في عملية التصريف compiling

int getSquareSides()
{
    return 4;
}

#endif // SQUARE_H
#endif // GEOMETRY_H

int main()
{
	// ...
    return 0;
}

يمكنك أن تقرأ أكثر حول الـ Header guards من خلال هذه المقالة هنا، حيث يتم شرح كيفية تضمين ملفات الترويسة Headers بطيرقة صحيحة:

 

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...