• 0
محمد علاء الدين

ال Overloading و ال Type Checking

سؤال

منذ فتره كنت قد صنعت فئه تتعامل مع النصوص واليوم قمت بإضافة مجموعة دوال جديده لها خاصه بدمج النصوص و التصريح الخاص بهم كالتالى:


char* Concat(const char* s1, const char* s2);

char* Concat(const char** src, int size);
char* Concat(const char** src, int size, int start_idx);
char* Concat(const char** src, int size, int start_idx, int count);
char* Concat(const char** src, int size, const char* delimit);
char* Concat(const char** src, int size, const char* delimit, int start_idx);

char* Concat(const char** src, int size, int start_idx, int count, const char* delimit);

و بدون اسماء المعاملات لتسهيل قرائتهم


char* Concat(const char*, const char*);

char* Concat(const char**, int);
char* Concat(const char**, int, int);
char* Concat(const char**, int, int, int);
char* Concat(const char**, int, const char*);
char* Concat(const char**, int, const char*, int);

char* Concat(const char**, int, int, int, const char*);

2Cجميع الدوال ماعدا الدالتين الأولى و الأخيره تم تعريفهم inline داخل الـ header file و يقوموا بإستدعاء الداله الأخيره حيث انها هى الداله الرئيسيه.

قمت بكتابة الكود التالى داخل ملف كود لإختبار الدوال:


#include <iostream>
#include "strlib.h" // my class nae is StrLib
using namespace std;

void main()
{
const int ArraySize = 4;
char* ppstr[] = {"My", "name", "is", "Muhammad"};

char* retVal = StrLib::Concat(ppstr, ArraySize, " ");

cout << "Before Concating\n";

for(int i=0; i<ArraySize; i++)
cout << "Element " << i+1 << ppstr[i] << endl;

cout << "After Concating with space as delimit character\n";

cout << retVal << endl;
}

و لكن المترجم يعترض عن السطر التالى


char* retVal = StrLib::Concat(ppstr, ArraySize, " ");

رسالة الخطأ تقول


error C2665: 'Concat' : none of the 7 overloads could convert all the argument types

و داخل شاشة الـ output يظهر تفصيل اكثر عن الخطأ و هو


error C2665: 'Concat' : none of the 7 overloads could convert all the argument types
could be 'char *Concat(const char **,int,int)'
or 'char *Concat(const char **,int,const char *)'
while trying to match the argument list '(char *[4], const int, const char [2])'

و بعد البحث وجدت هذا الرابط داخل الـ MSDN ويعرض سبب المشكله و يوجد كود بسيط يظهر سبب الخطأ و كيفية حله


// C2665.cpp
void func(short, char*){}
void func(char*, char*){}

int main() {
func(0, 1); // C2665
func((short)0, (char*)1); // OK
}

مالا افهمه هو انه يوجد دالتين فقط بإسم Concat يأخذوا نفس العدد من المعاملات بإختلاف انواعهم و هم


char* Concat(const char**, int, int);
char* Concat(const char**, int, const char*);

الفرق بين الإثنين هو المعامل الثالث الأولى هى التى استدعيها،

صحيح ان كلاهما قد يقبل رقم و لكنى بداخل الكود قمت بتحديد ان القيمه المدخله هى مؤشر لنص (النص عبارة عن مسافة فارغه).

اذا كنت سأقوم بتمرير قيمة المعامل الثالث م 9 تحديد نوعه (عمل cast له لـ const char*) - و قد جربت و لم تنفع - فما فائدة الـ type checking اذا كنت سأحدد نوع المعامل الذى سأمرره.

حاولت معها و لم اجد لها حل، أرجو ان كان لدى احدكم حل لها ان يضففه.

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

7 إجابة على هذا السؤال .

  • 0

السلام عليكم ...

يا عم محمد, مالذي يدفعك للدخول في متاهات المؤشرات و أنت تبرمج بالعزيزة ++C, و فوق كل هذا لديك string class جاهز مجهز, من الأفضل لو أنك قمت بإضافة دوالك على شكل free functions

و الأفضل, أن تتخلى عن الفكرة من أساسها :P

عموماً الخطأ الذي يظهر لديك, ليس بسبب الـ " " و إنما بسبب المعامل الأول **const char

لنبدأ من البداية,


char* ppstr[]

يتم تحويلها بشكل تلقائي حسب مواصفات اللغة إلى:

char**

راجع: 4.2 Array-to-pointer conversion

ثم, تتم محاولة مطابقة هذا الـ argument مع:

const char**

حينها يجب على المترجم التوقف, لأن اللغة لا تسمح بهذا الأمر, راجع: 4.4 Qualification conversions

---- تعديل

لحل المشكلة, يجب عليك تعريف الـ parameter الأول على أنه مؤشر ثابت لمؤشر ثابت لحرف ثابت! لكي تحل جميع المشاكل التي ستواجهك في عملية الـaliasing ,ربما يكون هذا مضحكاً و لكن التعريف يجب أن يكون على الشكل التالي:

char* Concat(char const* const* const, int, int, int, const char*);

الأمر يتعلق بالـ aliasing rules عن طريق المؤشرات, و ماذا بعد؟ :)

السبب (المثال مذكور في المواصفات و ليس من عندي),

int main() {
const char c = ’c’;
char* pc;
const char** pcc = &pc; //1: not allowed
*pcc = &c;
*pc = ’C’; //2: modifies a const object
}

سؤال جميل جداً بالمناسبة,

تحياتي,

تم تعديل بواسطه Khaled.Alshaya
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

ذكرتني بمقولة أحد عمالقة ++C المسمى P.J. Plauger صاحب أحد أشهر الـ implementations لـ STL:

writing string classes is one of the more popular indoor sports among C++ programmers.

لهذا, مرحباً بك يا مبرمج الـ ++C :cool:

تم تعديل بواسطه Khaled.Alshaya
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

ربنا يبارك لك يا خالد، تم حل المشكله فعلا const بالمعامل الأول هى اللى كانت عاملها :clapping:

فوق كل هذا لديك string class جاهز مجهز

انا بعمل مترجم بسيط مبنى على لغة السى و بحمل الكود كله دفعه واحده داخل buffer و ببقى محتاج اعدل القيم اللى موجوده جوا الـ buffer عدة مرات، علشان كده الفئه string لم تعمل معى.

من الأفضل لو أنك قمت بإضافة دوالك على شكل free functions

انا كنت عامل كده بس بسبب ان فى دوال تانيه لها نفس الإسم فشلت الفكره دى و لا يوجد بديل لإستخدام فئه كحاويه لـ static functions، لو فيه عندك فكره افضل من الفئه الحقنى بيها.

بالنسبه لـ const لما تكون معرفه مع معامل فهذا يعنى ان هذا المعامل لن يتم تعديل القيمه التى يشير إليها من داخل الداله و هذا يتيح تمرير قيم لهذا المعامل اقل فى درجة الحمايه مثل متغيرات او قيم مجرده، هذا يحدث مع المصفوفات ذات البعد الواحد.

بالنسبه للمصفوفات ذات البعدين فإن المترجم يقوم بالتفرقه ما بين الـ static array و الـ dynamic array حيث لا يتيح تمرير ايهما للأخر مع انهما فى النهايه يتم تحويل الصيغه الخاصه بهم إلى مؤشر لمؤشر لنوع معين، الأمر محير بالنسبه لى.

بالنسبه للمثال الخاص بالكاتب يمكن التحايل على تعديل مؤشر بإستخدام const_cast او حفظ قيمة المؤشر داخل void* و من ثم إعادتها مره اخرى إلى نوعها بدون const و من ثم تعديلها و إليك مثال


// modify const pointer using const_cast

const char tmp[] = "Arab Team 2000";
cout << tmp << endl;

char* tmp2 = const_cast<char*>(tmp);
tmp2[13] = '5';
cout << tmp << endl;

// modify const pointer using void*

const char tmp[] = "Arab Team 2000";
cout << tmp << endl;

char* tmp2 = (char*)(void*)&tmp;
tmp2[13] = '5';
cout << tmp << endl;

المثال يعمل معى على visual studio 2008.

دعنا من مثال الكتاب و لنتكلم عن المصفوفه الثانئية الأبعاد (حيث انى استخدمها بكثره)، لما لا يقبل المترجم بعملية التحويل، و حتى و ان كان المعامل غير معرف بـ const لا يقبل عملية التحويل ايضا؟ فهل تعلم السبب.

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أهلاً أخي محمد,

لاحظ أن عملية const_cast على متغير معرف على أنه ثابت أصلاً, عبارة عن undefined behavior. بالتالي, الكود الذي وضعته أصلاً خاطئ من ناحية اللغة, و لكنه ليس خطأً في الـ syntax, و إنما خطأ logical إن صح أن نسميه كذلك,

في أحسن الأحول, يمكن أن تقوم بذلك إن كنت تعرف أن الـ constant في المنصة التي تعمل عليها (تعرف 100% و ليس تكهن) سيتم تخزينه في منطقة قابلة للقراءة و الكتابة, و ليس للقراءة فقط, فربما يكون مكان الثوابت في الـ ROM أو منطقة محمية من الكتابة و هكذا,

و كما ترى, هذا عبارة عن Implementation Detail, و اللغة تقول لك بأن تعديل ثابت عملية غير معرفة بقوانين اللغة.

بالمناسبة, أعطنا بعض الأمثلة حول ما تريد فعله في النص الذي لديك, فالـ string class غالباً ما يؤدي الغرض, و هناك بعض الأدوات في boost يمكن أن نأخذ عنها فكرة سريعة لربما تساعدك في الأمر,

شاركنا بما وصلت إليه حتى و لو برؤوس أقلام, فأنا مهتم بموضوع الـ parsing و المترجمات أيضاً, بشكل عام لدي اهتمام في الـ front-end لمفهوم المترجمات, أنا متأكد أننا سنخرج بشيء مفيد و جديد :)

تحياتي,

تم تعديل بواسطه Khaled.Alshaya
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
لاحظ أن عملية const_cast على متغير معرف على أنه ثابت أصلاً, عبارة عن undefined behavior.

:lol: يبدو ان كل الأكواد اللى انا اعرفها بيتضح فى النهايه انها undefined behavior، شكرا جدا لهذه المعلومه حيث اننى لم اكن اعرفها.

بالنسبه للعمليات التى احتاج عملها على نص معين فلن استطيع قولها و لكن سأريك الدوال التى قمت بكتابتها و انت قل لى ما الموجود و ما غير الموجود منها فى الفئه string.


// get length of a string
int Length(const char* src);

// compare two strings in a range with able to ignore case
bool Compare(const char* s1, int s1_start_idx, const char* s2, int s2_start_idx, int count, bool ignoreCase);

// concat two strings
char* Concat(const char* s1,const char* s2);

// concat an array of strings in range with delimit
char* Concat(char** src, int size, int start_idx, int count, const char* delimit);

// check string for value existance
bool Contains(const char* src, const char val, bool ignoreCase);
bool Contains(const char* src, const char* val, bool ignoreCase);

// count value existance in string using range
int CountOf(const char* src, const char val, int start_index, int count, bool ignoreCase);
int CountOf(const char* src, const char* val, int start_index, int count, bool ignoreCase);

// create new string based on src string
char* Duplicate(const char* src);

// check if src ends with char or a string
bool EndsWith(const char* src, const char chr, bool ignoreCase);
bool EndsWith(const char* src, const char* str, bool ignoreCase);

repeat a value in src
bool Fill(char* src, const char chr, int count);
bool Fill(char* src, const char* str, int count);

// get index of a value founded in src in a range
int IndexOf(const char* src, const char find, int start_index, int count, bool ignoreCase);
int IndexOf(const char* src, const char* find, int start_index, int count, bool ignoreCase);

// get an array of indexes of a value founded in src
int* IndexesOf(const char* src, const char chr, int start_index, int count, bool ignoreCase, int& resultLen);
int* IndexesOf(const char* src, const char* str, int start_index, int count, bool ignoreCase, int& resultLen);

// check if src string is in lower case in a range
bool IsLower(const char* src, int start_index, int count);

// check if src string is in upper case in a range
bool IsUpper(const char* src, int start_index, int count);

// check if src string is a whitespace(Space,Tab) in a range
bool IsWhiteSpace(const char* src, int start_index, int count);

// get last index of a value in range
int LastIndexOf(const char* src, const char find, int start_index, int count, bool ignoreCase);
int LastIndexOf(const char* src, const char* find, int start_index, int count, bool ignoreCase);

// remove a range from string
bool Remove(char* src, int start_index, int count);

// remove a character from string in range
bool Remove(char* src, const char chr, int start_index, int count);

// replace a value from src in range
bool Replace(char* src, const char find, const char replace, int start_index, int count);
bool Replace(char* src, const char* find, const char replace, int start_index, int count);
bool Replace(char* src, const char find, const char* replace, int start_index, int count);
bool Replace(char* src, const char* find, const char* replace, int start_index, int count);

// reverse a range from src
bool Reverse(char* src, int start_index, int count);

// split source string
char** Split(const char* src, const char seprator, bool removeEmptyEntries, int& resultLen);
char** Split(const char* src, const char* seprator, bool removeEmptyEntries, int& resultLen);

// check src string if its start with a value
bool StartsWith(const char* src, const char chr, bool ignoreCase);
bool StartsWith(const char* src, const char* str, bool ignoreCase);

// substring a src in range
char* SubString(const char* src, int start_index, int count);

// make src string in lower case
bool ToLower(char* src, int start_index, int count);

// make src string in upper case
bool ToUpper(char* src, int start_index, int count);

// trim src string from start and end
bool Trim(char* src);

// trim src string from end
bool TrimEnd(char* src);

// trim src string from start
bool TrimStart(char* src);

لكل لكل داله بالأعلى مجموعه من الدوال الـ inline و التى تحتوى على مجموعه اقلا من المعاملات و التى يمكن تكوينها من معاملات اخرى.

قمت بتضمين جزء كبير منهم، متوقف عند الداله Remove و لم اقم بتضمين الداله IndexesOf بعد.

بالنسبه للمترجمات اغلب الكتب للأسف تشرح من ناحية رياضيه او بمعنى ادق شرح لنظريات دون تطبيق او حتى وجود خوارزميات، لذا فبجانب دراستى لهذه الكتب يوجد كتابين اخرين ممتازين فى هذا المضمار اولهم كتاب A Small-C Compiler شرح كامل لتصميم مترجم C يحتوى على بعض امكانيات اللغه بالإضافة لجزء كبير من المكتبه الـ Standard الخاصه به، الكتاب قديم بعض الشئ لإنه البرامج الناتجه من المترجم تعمل داخل بيئة DOS.

الكتاب الثانى و هو Game Scripting Mastery و يشرح لك كيفية صنع Virtual Machine بالإضافة للـ Runtime Environment مع مترجم، الـ Syntax الخاص بلغة الـ VM (الـ Assembler) يقارب الخاص بالـ Assembly لبروسسور Intel x86 و المترجم الخاص باللغه عالية المستوى (الـ Compiler) الـ Syntax الخاص به ما بين Java Script و C و فى النهايه يجعلك تصمم Debugger للغه التى يطلق عليها XtremeScript.

الكتاب الأول قمت بتنسيقه و تنظيمه داخل ملف chm ستجده بالمرفقات، الكتاب الثانى ستجده فى هذه المشاركه الكتاب السابع.

A Small-C Compiler.rar

حيث ان الـ Debugger يتم تصنيعه جنبا إلى جنب مع المترجم لذا اعتقد ان هذا الكتاب سيهمك ايضا حيث يشرح انظمة الـ Debugger المختلفه و الخوارزميات المتعلقه بتضمينه، اسم الكتاب How Debuggers Work قمت بإضافته فى المرفقات ايضا.

How Debuggers Work.rar

و الله ولى التوفيق

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أهلاً أخي محمد,

لحسن الحظ ما تطلبه موجود في string class, و إن لم يكن موجوداً فيه, فستجده في الـ standard algorithms, و علاوة على ذلك, ألق نظرة على قسم String and text processing في Boost, و خصوصاً الخوارزميات البسيطة.

بالمناسبة, التعامل مع المؤشرات بهذا الشكل, سيجعلك تكره الساعة التي فكرت فيها البدء بمشروع كهذا, صدقني, طلب مني مرة مشروع في الجامعة بلغة الـ C لمعالجة النصوص - بسيط إلى حد ما - و لم أستطع اقناع الدكتور باستعمال ++C :P

عموماً, اللغة التي تود بناؤها, هل يتوفر لها Grammar, تحديداً BNF أو EBNF؟ إذا كان كذلك, هذا سيبسط المشروع إلى درجة كبيرة, و سيجعلك تهتم أكثر بكتابة الـ semantic rules و من ثم كتابة مفسر أو virtual machine بسيطة, للغة.

تحياتي,

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

حقيقى لابد ان ادرس boost، فى كل مره اجد فيها الكثير و المفيد.

بالنسبه للغه فهى لا تعتمد على BNF أو EBNF، حيث ان الـ Grammer الخاص بها بسيط جدا، حتى انها typeless. انا فقط اقوم بتطبيق افكار محدده و اتقنها ثم انتقل لما بعدها حتى اصبح ملم بالأمر بأكمله و بعدها اصنع مشروع تطبيقى يحتوى على كل الأفكار مجتمعه.

و الله ولى التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .