الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

من سي++ إلى سي #

مغلق
بدأه هاني الأتاسي في 4 مارس 2002 · 17 رد · 5,162 مشاهدة · في C++.Net
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

المقالة مصدرها http://msdn.microsoft.com/msdnmag/issues/0...p/ctocsharp.asp مع بعض الاختصارات ..

كل عشر سنوات تقريبا يجب على المطورين أن يضعو طاقاتهم في تعلم تقنيات جديدة. في بداية الثامانينات كان ال Unix و لفة السي هي المسيطرة ومن ثم في التسعينات بدأ المطوريين بتعلم وندوز والسي++ والآن ظهرت تقنية .NET وال سي شارب .. طبعا تعلم لغة وبيئة جديدة يأخذ الوقت والجهد الكثير ولكن لحسن الحظ فإن تصميم البرمجيات في سي # وتقنية .NET لم يختلف كثيرا عن الوندوز والسي++ . في هذه المقالة سوف أوضح بعض الفروقات التي يحتاجها مبرمج السي++ للانتقال إلى السي # .

هناك بعض المقالات التي تتطرقت إلى التحسينات التي أضيفت إلى السي # (http://msdn.microsift.com/msdnmag/issues/0...sharp/cshar.asp) . في هذه المقالة سوف أوضح أهم النقاط الضرورية للانتقال من سي++ إلى سي شارب . هذه النقاط هي : الانتقال من بيئة غير منظمة إلى بيئة منظمة ، و الثغرات التي سوف تواجه مبرمج السي++ ، بعض الميزات والتحسينات التي سوف تؤثر على طريقة برمجتك .

الانتقال من بيئة غير منظمة إلى بيئة منظمة:

السي++ هي لغة صممت كلغة غرضية التوجه منخفضة المستوى قليلا يمنح المبرمج بها التحكم الكامل والمرونة الكاملة بالتحكم بالأنواع . أما السي شارب صممت لتكون عالية المستوى وأيضا غرضية التوجه . على سبيل المثال في السي++ فإنك تتحكم بشكل تام بعملية بناء العناصر ومحل توضعهم في الذاكرة ، يمكن أن تضعهم بالمكدس أو في الكومة Heap . في سي شارب الأنواع البسيطة ك int و double فهي دائما بالمكدس أما ال classes فهي في الكومة .

أيضا في السي شارب لن تتحكم بشكل مباشر بمدة بقاء العناصر في الذاكرة . السي شارب لاتحتوي على destructor أو هادم كما هو في السي++ . يوجد ما يسمى بمجمع النفايات أو Garbage Collector سوف يقوم بافراغ العناصر من الذاكرة بعد مدة بسيطة عندما لا يوجد أي كود يستخدم الكائن أو العنصر .

بنية السي شارب جعلتها تفتقر لبعض الأمور المهمة الموجودة في السي++ مثلا الوراثة المتعددة (multiple inheritance) واستخدام القوالب Templates . وذلك بسبب أن برمجة امكانية الوراثة المتعددة في بيئة منظمة ولا تحتوي على هادم صعب جدا وأيضا بسبب أن الأنواع العامة لم يتم اضافتها للسي شارب generics .

الانواع البسيطة في سي شارب ماهي إلا عبارة عن وصلة إلى أنواع اللغة الموحدة أو

oCommon Language Runtime . مثلا int هو نفسه Systen.Int32 .

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

عثرات مبرمجي السي++ في السي شارب:

في الحقيقة سي شارب تشبة السي++ وهذا مايجعل الانتقال لها سهل وأيضا يجلب المشاكل أيضا . مثلا لو كتبت كود سي++ صحيح مائة بالمائة فإنه لن يترجم في سي شارب والأفظع من هذا فإنه قد لا ينفذ بالشكل الذي نريد. معظم القواعد البرمجية تغيرت عن سي++ ، مثلا لا يوجد فاصلة منقوطة بعد تعريف الكلاس . Main الآن تبدأ بحرف كبير .

هذه الوصلة : http://dotnet.oreilly.com/news/programming...sharp_0801.html توضح 10 أخطاء ممكن أن يقع بها مبرمج السي++ .

الأنواع ذات قيمة value وذات دليل reference :

السي شارب تفرق بين أنواع ال value وال referencce . الأنواع البسيطة ك int , long , double و الstruct كلها عبارة عن value types .. أما الclasses كلها تعامل كأنواع reference . أنواع ال value تحفظ قيمتها بالمكدس كما ال varaibles في السي++ أما أنواع ال reference فتحفظ في المكدس قيمة مؤشر إلى الكلاس الذي يكون في الكومة heap وهي متل المؤشر في السي++ . بالنسبة إلى التمرير إلى التوابع فأنواع الvalue تمرر عن طريق قيمتها by value أي يتم عمل نسخة أخرى بالذاكرة أما أنواع الreference فيتم تمريرها عن طريق هذا الدليل ..

المختصر أن نوع الreference في السي شارب هو بشكل آلي للكلاسيس أما في السي++ فيجب أن يتم ذكر ذلك عن طريق العامل & للكلاسيس أو للأنواع الأخرى .

ال Structs :

ال struct مختلف تماما في السي شارب . في السي++ كما نعلم فإن الstruct هي نفسها الclass والفرق الوحيد أن الوصول الافتراضي لل struct هو public أما الكلاس فهو private . الstruct في سي شارب مختلف تماما عن الكلاس . هي مصممة في السي شارب من أجل أن تحتوي على كائنات بسيطة والstruct عبارة عن أنواع ذات قيمة وهي بالتالي تمرر بقيمتها . وايضا الstruct لا يمكن أن يشتق منه حيث يعتبر بنية معطيات مقفلة أي لا يمكن أن يعدل بها . وأيضا الstruct هو أكفأ من الclass من ناحية البناء وهي الأفضل من الكلاس في حالة احتواء عناصر قليلة .

سوف أكمل إن شاء الله قريبا..

Coding on the Cloud and for the Cloud!

My Blog

#2

حلو كثير هاني

الله يعطيك العافية

أنا في انتظار التكملة

تم تعديل هذه المشاركة بواسطة cold0zero في 11 يونيو 2004 في 07:16

#3

Thanks Mr. Hani

I really enjoyed that article

Now I do realize that the C++ section is going to be active again.

Thanks again

#4

مشكور أخي هاني على هالمقال

بس إنا ما راح أستفيد منو ( لأدخل في السي++ أول )

عموماً تسلم كثير كثير ولو إنا ما نشوفك زي أول

مع تحياتي ,,,

تم تعديل هذه المشاركة بواسطة cold0zero في 11 يونيو 2004 في 07:17

#5

كلام جميل يا أخ هاني .. وبإنتظار بقيته ;)

#6

اشكرك أنس على الاهتمام

أخ عبقري شكرا جدا .. أي بس قسم السي++ من زمان نشط

طلال ! الله وحده يعلم كم أنا مشغول يعني إذا قصرت في المنتدى إن شاء الله في غيري بيجاوب على الاسئلة .

أخ ملك الشبكات شاكر لك وكل يوم ححط شوية ..

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

كل شئ موروث من Object :

في لغة السي شارب كل شئ موروث من كلاس اسمه Object . هذا يتضمن الكلاسات التي تقوم بانشائها بالاضافة إلى الأنواع البسيطة التي تستخدمها كال int و double و أيضا ال structs . هذا الكلاس يقدم خدمات جدا مفيدة لشتى أنواع المعطيات . أهمها والتي سوف نتحدث عنها هنا هو التابع الوهمي virtual وهو ToString (أقصد بvirtual أي كما في السي++ عندما نعرف التابع virtual فيمكن أن نعيد تعريفه عندما نورث من الكلاس) . على فرضا طباعة أي رقم يحتاج إلى تجويل هذا الرقم إلى سلسلة . طباعة كلاس التاريخ سوف يقتضي تحويل التاريخ من بيانات مسجلة كint مثلا إلى تاريخ مقروؤ . هذا كل مانريده من ToString؛ هو تحويل بنية المعطيات إلى سلسلة فرضا من أجل طباعتها .

المكافئ ل cout في السي++ هو التابع System.Console.WriteLine . طبعا كل التوابع موروثة من System وفي ال System نجد الكلاس Console المسؤول عن التعامل مع نافذة ال Console وفي الكلاس Console نجد مجموعة من التوابع أحدها WriteLine الذي يطبع سطر وReadLine المسؤول عن قرائة سطر يدخله المستخدم .

في معظم برامج السي شارب نجد عبارة using System في الأعلى وهي تماما مثل using namespace في السي++ . وهي تعني أن يتم بشكل آلي استخدام ال scope تبع ال namespace أو الكلاس الذي يذكر بعدها . وبالتالي إذا كتبنا العبارة السابقة في سي شارب ليس من الداعي ذكر System عند تعريف المتحولات ك Int32 أو Int64 أو حتى عند استخدان console بل فقط نذكرها كالتالي Console.WriteLine . دائما أخطأ وأكتب WriteLn كما في الباسكال (بصراحة cout أقصر واشيك .. لا أدري لماذا مياكروسوفت تحب أن تخالف جميع البشر والمقاييس وتحضر أسماء من عندها) .

من أجل استخدام WriteLine فإنه بكل بساطة تكتب السلسلة التي تريد طباعتها وتضمن بداخلها الأماكن التي تريد أن تعوض عنها كما في الprintf ولكن يختلف الأمر قليلا هنا حيث ليس من الداعي ذكر نوع المتحول الذي تريد طباعته كما في مقطع الكود التالي :

Console.WriteLine("The employee: {0}, the counter: {1}", myEmployee, myCounter);

بين الأقواس 0 تعني طباعة المتحول الأول وهكذا ...

التابع WriteLine يقوم باستدعاء التابع الوهمي ToString الموجود في كل متحول والتعويض عن السلسلة التي ترجعها ToString بدلا من الأقواس والأرقام. طبعا كما هو الحال في أي تابع virtual فإنه يمكن في الclass أن تعيد تعريف هذا التابع لكي تعطيه لمسة خاصة . الكود الافتراضي للتابع ToString في الكلاس Object يعيد اسم الكلاس المورووث من Object وهذا ماسوف تراه في المثال المرفق .

ماذا يحدث إذا مررت قيمة عدد integer إلى WriteLine يعني مثلا 42 (لا يمكنك استدعاء ToString عليه) .. لذلك المترجم بشكل ضمني وداخلي يقوم بتغليف هذه القيمة المباشرة بكائن من نوه object وعندما WriteLine تستعي ToString هذا الكائن سوف يرجع القيمة الثابتة .

وهذا مثال مكتوب بالسي شارب يشرح السابق :

using System;

// A Class which doesn't override ToString
public class Employee
{

}


// A Class which does override ToString
public class Counter
{
	private int theVal;

	public Counter(int theVal)
	{
  this.theVal = theVal;
	}

	public override string ToString()
	{
  Console.WriteLine("Calling Counter.ToString()");
  return theVal.ToString();
	}
}


public class Tester
{
	// Note that Main has a capital M
	// and is a static member of a class
	public static void Main()
	{
  // Create an instance of the class
  Tester t = new Tester();

  // Call the non static member
  t.Run();	
	}

	// The non static method which demonstrates 
	// calling ToString and boxing
	public void Run()
	{
  Employee myEmploee = new Employee();
  Counter myCounter = new Counter(12);

  Console.WriteLine("The employee: {0}, the counter value: {1}",
 	 myEmploee, myCounter);

  // Note that integer literals and variables are boxed
  int myInt = 5;
  Console.WriteLine("Here are two integers: {0} and {1}", 17, myInt);

  // Just to wair for an input
  Console.ReadLine();
	}
}

البرنامج السابق سوف يعطي الخرج التالي :

Calling Counter.ToString()
The employee: Employee, the counter value: 12
Here are two integers: 17 and 5

نلاحظ في الكود مايلي :

  • لاحظ تعريف الclass ليس بعده فاصلة منقوطة .
  • كل متحول يجب أن يسبقه مداه ك public أو private وهذا شبيه بالجافا
  • من أجل التفريق بين البارامتر في باني الكلاس Counter والعنصر في الكلاس استخدمنا this تماما كما في سي++
  • يجب ذكر override قبل التابع إذا أردنا أن تعيد تعريفه وهذا شبيه بالباسكال
  • البرنامج يجب أن يكون داخل كلاس ولاحظ التابع Main يجب أن يكون من التوابع ال static في هذا الكلاس ووظيفة هذا التابع فقط بناء كائن لهذا الكلاس في الكومة وتمرير التنفيذ لتابع غير static .
  • لاحظ كيف تمت عملية بناء كائنات الكلاسات عن طريق new لتكون في الكومة وليس في المكدس .
  • لم يتم استخدام delete (أساسا لا يوجد delete في سي شارب) لأن الGarbage Collector سوف تقوم بشكل تلقائي بازالة الكائنات من الذاكرة بعد فترة بسيطة بعدما لا يكون أي جزء من الكود يستخدمها (أي ال reference counter يصبح 0) وهذا أيضا أشبهه بالدلفي .

غدا سوف نتكلم عن البارامترات من نوع ref ..

تم تعديل هذه المشاركة بواسطة cold0zero في 11 يونيو 2004 في 07:20

Coding on the Cloud and for the Cloud!

My Blog

#7

بارامترات من نوع Ref ومن نوع Out

كما في السي++ فإن التوابع ترجع قيمة واحدة . طبعا يمكن استخدام بارامترات التوابع من أجل ارجاع أكثر من قيمة . في السي++ كان ذلك يتم بتمرير مؤشر أو دليل إلى الكائن أو المتحول ومن داخل التابع يمكن الوصول إلى محتويات هذا الكائن الأساساية والتعديل عليها . في سي شارب كما رأينا فإن جميع الكائنات التي هي كانة كلاس بالأصل يتم التعامل معها كدليل أو reference لذلك ليس لها أي معاملة خاصة هنا عند تمريرها إلى التوابع . أما الأنواع البسيطة من نوع value . فهي تحتاج إلى اضافة ref قبل تعريف البارامتر في التابع كالتالي :

public void GetStats(ref int age, ref int ID, ref int yearsServed)

أيضا يجب أن تنتبه إلى أنه سوف يقتضي عليك أيضا استخدام الكلمة المحجوزة ref عند استدعاء التابع كالتالي :

int age = 22, ID, yearsServed = 2;
ID = 10;
Fred.GetStats(ref age, ref ID, ref yearsServed);

الآن طبعا يمكنك من تعريف المتحولات age و ID و yearsServed في التابع المستدعي وسوف تعاد قيم بهذه المتحولات. من أجل استخدام ref يجل أن يكون المتحول معرف ومسند له قيمة أي يكون مهيئ .

الآن ماذا لو لم نقم بتهيئة المتحولات السابقة . طبعا هذا لن يعمل ولكن يوجد نوع آخر من البارامترات يسمى out الذي يسمح لك بتمرير متحولات غير مهيئة ويتم تهيئتها بالداخل كالتالي :

public void GetStats(out int age, out int ID, ref int yearsServed)

والاستدعاء يكون كالتالي :

int age, ID, yearsServed;
Fred.GetStats(out age, out ID, out yearsServed);

سوف نتكلم غدا عن المعامل new ..

تم تعديل هذه المشاركة بواسطة cold0zero في 11 يونيو 2004 في 07:27

Coding on the Cloud and for the Cloud!

My Blog

#8

آسف يااخوان على الخطأ في الرد السابق .. حيث استخدمت المصطلح معرف define بدل من استخدام مهيئ initialized .. لذا أرجو العودة وقرائة من عند مثال ال ref ..

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

استدعاء New :

في السي++ كان المعامل new يقوم بحجز كائن في الheap أو الكومة أنا في سي شارب فالأمر يختلف قليلا . فإذا كنت تستدعي new على كلاس فالكائن سوف يكون في ال Heap وإذا كنت تستدعيه على متحولات من نوع value كال struct فالكائن سوف يكون في المكدس ويتم استعاء الباني أيضا في هذه الحالة.

في الواقع يمكنك أن تنشئ كائن ال struct في المكدس من غير استخدام new . لكن انتبه new تقوم بتهيئة العنصر باستدعاء الباني إذا كان يوجد باني أو باسناد أصفار إذا لم يوجد باني. إذا لم تستخدم new يجب أن تقوم بتهيئة جميع العناصر التي داخل struct قبل أن يمكن استخدامها .

انظر البرنامج التالي :

using System;

// a simple struct with two member 
// variables and a constructor
public struct Point
{
	public Point(int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	public int x;
	public int y;
}

public class Tester
{
	public static void Main()
	{
		Tester t = new Tester();
		t.Run();
	}

	public void Run()
	{
		// Test 1
		//
		Point p1 = new Point(5, 12);
		SomeMethod(p1);		// fine

		// Test 2
		//
		Point p2;

		// هذا لن يعمل لأننا لم نقم بتهيئة المتحول
		// p2
		// SomeMethod(p2);

		p2.x = 1;
		p2.y = 2;

		SomeMethod(p2);	// fine

		// Test 3
		Point p3;

		SetMethod(out p3);
		SomeMethod(p3);		// fine too
	}

	// a method we can pass the point to
	private void SomeMethod(Point p)
	{
		Console.WriteLine("Point at {0} x {1}", p.x, p.y);
	}

	private void SetMethod(out Point p)
	{
		p.x = 10;
		p.y = 20;
	}
}

وخرج البرنامج السابق هو :

Point at 5 x 12
Point at 1 x 2
Point at 10 x 20

غدا سوف نتكلم عن Properties ...

Coding on the Cloud and for the Cloud!

My Blog

#9
(k)
#10

معلــــــــــــش حبيبي.. هاني... سؤال غلط..

أنا ما أعرف لسي ++ .. وأنت شوقتني للسي شارب.. وأنا تقريبا متمكن من سي.. فهل ..رأيك أتحول للسي شارب مباشره .. أو أبداء في سي ++ .. مع أني لسا بادي أقرا فيها.. بس مو فيجول.. برمجه عاديه؟؟؟؟ .. السؤال موجه للجميع هنا. ومشكور.. على الشرح الجميل.

014.gif
#11

السلا معليكم،

يا بطران، لا تضيع وقتك في تعلم القديم أو البرمجة به (إلا إذا كنت متمكن منه بالأصل). أما إن كنت جديد في البرمجة، أو راغب في التطوير، فلا تتعلم إلا الجديد وواكب العصر واتبع دروس الاستاذ هاني في ذلك،

برمج بالجديد السهل المنتشر c#.

#12

آسف ، طلع عندنا 2 الأتاسي!!، على كل حال ننتظر تكملة الدروس من كليهما.

#13

السلام عليكم ورحمة الله وبركاته

مبروك للاخ محمد هاني الاتاسي الادارة

وشكرا للجميع

#14

آسف شباب .. أنا هو هاني نفسه .. أنا اسمي الأصلي محمد الهاني يعني مركب ... المهم آسف للتأخير وهذا بعض التكملة .

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

الخواص properties :

معظم مبرمجين السي++ يحاولون أن يضعو العناصر member variables في قسم ال private من الكلاس . وذلك لحفظ التأثير عليها من خارج الكلاس بشكل خاطئ. طبعا هذا يقتضي باضافة توابع خاصة بالوصول إلى هذه المتحولات : أحدها يكون لأخذ القيمة وهو const والثاني يكون لاسناد قيمة ، وهما ليسا اجباريين .

في السي # الوضع مختلف قليلا . حيث هنا عند تعريف أي متحول يمكن أن نقوم أيضا بتعريف property تحمل تابعين : واحد للقرائة get والآخر للكتابة set. أي عند أخذ قيمة المتحول سوف يتنفذ ماهو داخل التابع get وعند اسناد قيمة لهذا المتحول سوف يتم تنفيذ ماهو داخل التابع set.

يمكن أن نضيف في الكلاس emploee السابق الخاصية Age كالتالي :

public class Employee
{
	public int Age
	{
		get
		{
			return age;
		}
		set
		{
			age = value;
		}
	}

	private int age;
}

الكلمة المحجوزة value تكون متوفرة للخاصية property في حالة get وهي تحمل قيمة مابعد معامل الاسناد مثلا :

Fred.Age = 17;

ف value هنا سوف تحمل القيمة 17 .

طبعا يمكنك انشاء خاصية قابلة للقرائة فقط وهذا يتم بتعريف التابع get فقط . وسوف يعطي المترجم خطأ عند محاولة اسناد قيمة إلى هذه الخاصية .

طبعا هذا التصميم في عملية تغليف المتحولات سوائا هنا او في السي++ جيد وذلك مثلا إذا أردنا أن نتعامل مع قاعدة بيانات بدلا من متحول في الكلاس فما علينا إلا أن نغير الكود في get و put ولن يتأثر البرنامج الذي يستخدم الكلاس خاصتنا.

ملاحظة : في Microsoft Visual C++ توجد اضافة تجعل عملية بناء ال properties مشابه إلى السي # ولكن هي ليست من ضمن بيئة لغة السي++ .

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

المرة القادمة سوف نتكلم عن المصفوفات .

Coding on the Cloud and for the Cloud!

My Blog

#15

WE ARE WITH YOU HANI,

#16

ممكن ألقي التحية بعض طول غياب ..... سلامي للجميع و خاصة للأخ هيثم و هاني .... بعد زمان يا هاني .... أتحفنا بخبراتك ..... على فكرة الله يعطيك العافية يا أستاذي العزيز - هاني - هل تعلم أنني تعرفت و تعلمت لغة C++ بفضلك .

مدونتي

http://mbnoimi.net

#17

ياأهلين بالعزيز أبو أحمد ,, كيفك ان شاء الله بخير وعافية ,, وينك انقطعت كل هالمدة ؟

ان شاء الله خير ,, ولا اتعصرت مع الجامعة ,, الله يخليك ويعافيك ,,

والمنتدى يحتاج لخبرتك وعطائك ,, فلدينا سيل أسئلة وتطويرات جديدة لاتنقطع ,, الله يسهل بس ,,

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#18

حمد الله على السلامه يا اخ C&DEL

بسم الله الرحمن الرحيم

إِنَّ الَّذِينَ آمَنُوا وَعَمِلُوا الصَّالِحَاتِ إِنَّا لَا نُضِيعُ أَجْرَ مَنْ أَحْسَنَ عَمَلاً

صدق الله العظيم

=================

Belal Mahmoud Younes

Solution Developer

Link Development a LINKdotNET subsidiary

Mobile : 010 89 69 772

E-mail : belalyounes@hotmail.com

هذا الموضوع مغلق.

مواضيع مشابهة