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

كيف يمكن اعادة تعريف المعامل [] داخل الفئات

بدأه C++er في 5 أكتوبر 2009 · 18 رد · 1,087 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

يمكن إعادة تعريف المعامل [] داخل الفئات لجعلها تعمل مثل المصفوفه احادية البعد، و لكن كيف يمكن اعادة تعريفه ليعمل مثل المصفوفه المتعددة الأبعاد

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 5 أكتوبر 2009 في 06:52

مدونتي: C++ Tips and Tricks

#2

السؤال غير واضح ضع مثال الى ما تريد

#3
اقتباس
السؤال غير واضح ضع مثال الى ما تريد

إذا وضعت مثال لما اريد، إذا ما الهدف من السؤال :)

و لكن لتقريب الصوره هذا مثال على اعادة تعريف المعامل []

 

[color= #0000ff;]template [color= #000000;]<[color= #0000ff;]typename T[color= #000000;]>

[color= #0000ff;]class [color= #0000ff;]Array

[color= #000000;]{

[color= #0000ff;]public[color= #000000;]:

	[color= #0000ff;]Array[color= #000000;]([color= #0000ff;]int count[color= #000000;]) [color= #000000;]: size[color= #000000;](count[color= #000000;])

	[color= #000000;]{ arr [color= #000000;]= [color= #0000ff;]new T[color= #000000;][count[color= #000000;]]; [color= #000000;]}

 

	T[color= #000000;]& operator[color= #000000;][[color= #000000;]] [color= #000000;]([color= #0000ff;]int i[color= #000000;]) [color= #007f00;]// i is the index

	[color= #000000;]{ [color= #0000ff;]return arr[color= #000000;][i[color= #000000;]]; [color= #000000;]}

 

	~[color= #0000ff;]Array[color= #000000;]([color= #000000;])

	[color= #000000;]{ [color= #0000ff;]delete[color= #000000;][[color= #000000;]] arr; [color= #000000;]}

 

[color= #0000ff;]private[color= #000000;]:

	T[color= #000000;]*  arr;

	[color= #0000ff;]int size

[color= #000000;]}

السؤال الأن اذا قمت بجعل الفئه Array تمثل مصفوفه متعددة الأبعاد فكيف اقوم بإعادة تعريف المعامل [] ليتم استخدامه مع الفئه Array مثلما نستخدمه مع المصفوفات متعددة الأبعاد الإفتراضيه الخاصه باللغه ؟

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 5 أكتوبر 2009 في 08:41

مدونتي: C++ Tips and Tricks

#4

قم بعمل إعادة تحميل للقوسين () ، [] تأخذ رقم واحد فقط :) .

او اعمل كلاس تاني يرجه اول قيمة في عنصر المصفوفة

template <typename T>class 
helper {public:  const T operator[](int j) const; 
 T& operator[](int j);};
 template <typename T>
class array 
{
public:  
const helper operator[](int i) const;  
helper& operator[](int i);   // returns an object which overloads [] 
};

BEng , Electronics and communications.

Embedded systems engineer.

Graphics Programmer

عالم الكومبيوتر هو من لديه المعرفة في علوم الكومبيوتر ، الرياضيات ، هندسة الالكترونيات -احمد صالح

#5
اقتباس
قم بعمل إعادة تحميل للقوسين ()

هل تعطينى مثال على اعادة تعريف القوسين () لمثال الفئه Array بالأعلى ؟

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 5 أكتوبر 2009 في 10:35

مدونتي: C++ Tips and Tricks

#6

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

أخي محمد, هناك الكثير من الطرق, و لكن بشكل عام سيكون هناك مقايضة بين الأداء و بين عمومية الاستخدام. فمثلاً vector يعيد reference لنفسه, و هكذا.

خذ مثلاً هذا المثال:

struct oneD
{
	int elem[3];

	int& operator[](size_t index)
	{
		return elem[index];
	}
};

struct twoD
{
	oneD elem[3];

	oneD& operator[](size_t index)
	{
		return elem[index];
	}
};

int main()
{
	twoD matrix;

	matrix[0][0] = 0;

	int x = matrix[0][0];
}

كل مافي الأمر, هو أننا أعدنا مرجعاً لكائن آخر هو الآخر أعاد تعريف المعامل [].

هل عدد الأبعاد التي لديك ثابت أم متغير؟

هل يهمك سهولة كتابة الكود, لأن هناك طريقة أخرى عن طريق بناء proxy, لبناء مصفوفة متغيرة الأبعاد عالية الكفاءة, و لكن الأمر للأسف يحتاج إلى الكثير من الجهد و التجارب في هذه الحالة :)

تحياتي...

#7
اقتباس
هل عدد الأبعاد التي لديك ثابت أم متغير؟

عدد الأبعاد متغير

اقتباس
هل يهمك سهولة كتابة الكود

لا يهمنى سهولة الكود بقدر ما يهمنى كفاءة الأداء

اقتباس
هناك طريقة أخرى عن طريق بناء proxy, لبناء مصفوفة متغيرة الأبعاد عالية الكفاءة

كيف يمكن ان تتم هذه العمليه ؟؟

اقتباس
و لكن الأمر للأسف يحتاج إلى الكثير من الجهد و التجارب في هذه الحالة

على استعداد له بإذن الله و لكن اعرف كيف اولا.

و شكرا لك اخى.

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

مدونتي: C++ Tips and Tricks

#8

أهلاً محمد,

اقتباس
عدد الأبعاد متغير

حتى أكون صريحاً معك, الأمر أكبر من مستواي :)

يمكنك ببساطة فعل هذا الشيء بـ vector أو deque مع توفير ما تطلبه من استعمال [] بشكل متغير. و لكن هناك ضريبة في الكفاءة.

تصور مثلاً أن لدينا:

std::vector< std::vector<double> >

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

vector<double>

و من ثم يتم إدرجها في المصفوفة الكبيرة. هذا مثلاً لو أن لديك بعدان فقط.

ما تريد فعله موجود بالفعل, لذلك الحياة صعبة بدون boost في c++ :)

The Boost Multidimensional Array Library

لاحظ أن موقع المكتبة عندما يذكر المصفوفات الثابتة, وهو الشيء الذي يريد محاكاة عمله:

double matrix[3][3]

فإن المترجم يقوم بتخزين الـ 9 عناصر في أماكن متجاورة في الذاكرة. و يقوم بتوفير دالة تحويل للأبعاد على الشكل التالي:

matrix[j] == matrix[i*rowsize + j]

هذا بالطبع في اللغة نفسها.

عموماً, أتمنى أن تجد طريقة جيدة لحل الموضوع, و سأحاول أن أضع فكرة الـ proxy التي في رأسي في القريب العاجل :)

تحياتي...

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 5 أكتوبر 2009 في 20:47

#9

جزاك الله خيرا اخى خالد

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

مدونتي: C++ Tips and Tricks

#10

طيب ليه متتبعش الطريقة الطبيعية فى تعريف المصفوفات متعددة اﻷبعاد؟, و هى إنها مصفوفات ذات بعد واحد بس مكونة من مصفوفات.

Array< Array<int> > r;

و ساعتها ممكن تستخدم [] طبيعى و بأى عمق إنت عايزه على حسب تعريفك.

#11
اقتباس
طيب ليه متتبعش الطريقة الطبيعية فى تعريف المصفوفات متعددة اﻷبعاد؟, و هى إنها مصفوفات ذات بعد واحد بس مكونة من مصفوفات.

و ساعتها ممكن تستخدم [] طبيعى و بأى عمق إنت عايزه على حسب تعريفك.

فكره جميله ، هجرب و اضيف النتيجه

مدونتي: C++ Tips and Tricks

#12

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

طبعا يمكن في البداية عمل class سواء template أو none-template لكل من واحد من الأبعاد التي تريدها ، مثلا تريد بعدين 2D قم بعمل كلاس يعيد تعريف المعامل ( ) ومرر له البعدين (x,y) ، وهكذا بالنسبة للثلاثه أبعاد أو الأربعه ... طبعا حل غير عملي ويتطلب اعادة كتابة لكل من هذه الأبعاد :) .

الحل الأخر كما وضح أخ Blouteeth وكما قمت به في مثالك هو عمل class يمثل بعد واحد فقط وبعدها يمكنك انشاء عدد الأبعاد التي تريدها من خلال عمل Instantiating الclass من خلال الclass نفسه كأنه نوع بيانات ،، وهذا المثال :

#ifndef __ARRAYS__
#define __ARRAYS__

template <typename T >
class Arrays {
	public:
		Arrays (int aSize = def ) : size(aSize)  {
			ptrArray = new T [ size ];
		}

		const T& operator[] (int index) const {
			return ptrArray[index];
		}

		T& operator [] ( int index ) {
			return ptrArray[index]; 
		}

		~Arrays () {
			delete [] ptrArray;
		}

	private :
		int size;
		T* ptrArray;
		static const int def = 4; 
};

#endif // __ARRAYS__

ولتجربته :

// Arrays.cpp

#include <iostream>
using namespace std;

#include "Arrays.h"

int main ( int argc, char* argv[] ) {
	Arrays <int> oneDim(3);
	Arrays <Arrays<int> > twoDim(3);
	Arrays <Arrays<Arrays<int> > > threeDim(3);

	oneDim[0] = 10;
	twoDim[1][2] = 4;
	threeDim[1][2][2] = 3;

	cout << oneDim[0] << endl;
	cout << twoDim[1][2] << endl; 
	cout << threeDim[1][2][2] << endl;

	return (0);
}

والكود سوف يعمل على ما يرام ،، لكن الSyntax شويه متعب وممل لمستخدم الكلاس :) ..

هناك طريقة متقدمة في الtemplate تسمى template recursion ويمكن استخدامها في هذه الحالة (كتابة Real N-Dimensional Arrays) ،، لأن السطر :

Arrays <Arrays<Arrays<int> > > threeDim(3);

يمكن تصوره على أنه recursive فالأبعاد الثلاثه هي في الحقيقة Arrays من بعد واحد من Arrays من بعد واحد من Arrays من النوع int (يعتبر الbase-case) . وبدلا من جعل مستخدم الكلاس يقوم بهذه الخطوه الممله يمكنك توفير template recursion class وسوف يكون الإستخدام بهذا الشكل :

NArrays<int,1> oneDim;
NArrays<int,2> twoDim;
NArrays<int,3> threeDim;

الكلاس NArrays سوف يستقبل النوع وعدد الأبعاد في ال NArrays ، وبما أن أي عنصر من البعد الثالث سوف يكون هو NArrays من بعدين وأي عنصر في هذين البعدين سوف يكون NArrays من بعد واحد ، اذا سوف يكون لدينا في الكلاس مؤشر الى الكلاس NArrays من النوع المحدد والبعد -1 (3 هو 2 والذي هو 1 وهنا سيتم التوقف ) . أترككم مع المثال فلن تتضح الفكرة الا بالمثال :

template < typename T , int N >
class NArrays {
	public :
		NArrays () : size(def) {
			ptrArray = new NArrays<T,N-1>[size];
		}

		~NArrays(){
			delete [] ptrArray;
		}

		const NArrays<T,N-1>& operator [] (int index) const  {
			return ptrArray[index]; 
		}

		NArrays<T,N-1>& operator[] (int index) {
			return ptrArray[index];
		}

	private:
		int size;
		NArrays<T,N-1>* ptrArray;
		static const int def = 4; 
};

وسوف نقوم الأن بكتابة Partial specialization من الكلاس للbase case وهو البعد الأول الذي سيتوقف فيه.

template < typename T >
class NArrays<T,1> {
	public :
		NArrays (int aSize = def ) {
			ptrArray = new T [aSize];
		}

		~NArrays() {
			delete [] ptrArray;
		}

		const T& operator[] (int index) const  {
			return ptrArray[index]; 
		}

		T& operator [] ( int index ) {
			return ptrArray[index]; 
		}

	private :
		int size;
		T* ptrArray;
		static const int def = 4; 
};

ولتجربة المثال :

// NArrays.cpp

#include <iostream>
using namespace std;

#include "NArrays.h"

int main ( int argc, char* argv[] ) {
	NArrays<int,1> oneDim;
	NArrays<int,2> twoDim;
	NArrays<int,3> threeDim;

	oneDim[0] = 10;
	twoDim[1][2] = 4;
	threeDim[1][2][2] = 3;

	cout << oneDim[0] << endl;
	cout << twoDim[1][2] << endl; 
	cout << threeDim[1][2][2] << endl;

	return (0);
}

في المرفق نفس المثال من كتاب Professional C plus plus ويحتوي على زيادة دوال في الكلاس (Assignment , copy constructor وغيرهم ).. قمت بنسخه من الكتاب ووضعه في ملف cpp .

بالتوفيق ،،

Code.rar

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#13

جزاك الله خيرا اخى وجدى، هذه فعلا ما كنت اريد.

لدى سؤال

فى الكود التالى

 

 NArrays [color= #000000;]([color= #000000;]) [color= #000000;]: size[color= #000000;](def[color= #000000;]) [color= #000000;]{

            ptrArray [color= #000000;]= [color= #0000ff;]new NArrays[color= #000000;]<T,N[color= #ff0000;]-1[color= #000000;]>[color= #000000;][size[color= #000000;]];

        [color= #000000;]}

يتم انشاء الفئه Narray و يتم تمرير عدد الأبعاد فى كل مره بقيمه اصغر من سابقتها فمتى سيتم التوقف عن انشاء نسخ منها.

و ما فائدة النسخه NArrays<T,1> حيث انه لم يتم استخدامها.

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

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 08:22

مدونتي: C++ Tips and Tricks

#14

عندما يصل للبعد 1 ، وسسيتخدم حينها الPartial specialization وهنا الكلاس الجديد سينشئ في تلك اللحظه النوع T .

بالتوفيق ،

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#15
اقتباس
عندما يصل للبعد 1 ، وسسيتخدم حينها الPartial specialization وهنا الكلاس الجديد سينشئ في تلك اللحظه النوع T .

هل هذا يعنى انه اذا كتبت 20 داله داخل الفئه NArrays<T,N-1> لابد و ان اعيد كتابتهم داخل الفئه NArrays<T,1> ؟

مدونتي: C++ Tips and Tricks

#16

هذه هي ضريبة استخدامك للTemplate Recursion :) .. فالPartial specialization يجب أن يستخدم نفس الدوال بالضبط في الكلاس الذي قام بعمل specialization ، ويمكن أن يقوم بتغيير تطبيقها بما يلزم وأحيانأ تكون كما هي بالضبط ،،،

على العموم لا توجد طريقة متكاملة ،، وكلما أردنا التسهيل على مستخدم الكلاس سنجد المهمة أصبحت أكثر صعوبة من ناحية مبرمج الكلاس ، والعكس صحيح أيضا في حال أردنا تصعيب المهمه على مستخدم الكلاس..

بالتوفيق أخي الكريم محمد ،،

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#17

طب لو قلنا مثلا بدل من اعادة كتابة الفئة بأكملها لتكون ذات بعد واحد و قمت بوراثتها ببعد واحد و اقصد كالتالى

 

[color= #0000ff;]template [color= #000000;]<[color= #0000ff;]typename T, [color= #0000ff;]int D[color= #000000;]>

[color= #0000ff;]class NArray

[color= #000000;]{

	...

	...

	...

[color= #000000;]};

 

 

[color= #0000ff;]template [color= #000000;]<[color= #0000ff;]typename T[color= #000000;]>

[color= #0000ff;]class NArray [color= #000000;]: [color= #0000ff;]public NArray[color= #000000;]<T,[color= #ff0000;]1[color= #000000;]>

[color= #000000;]{

	...

	...

	...

[color= #000000;]};

الكود السابق هو نظرى اى لم اطبقه.

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

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 08:45

مدونتي: C++ Tips and Tricks

#18

المشكلة سوف تكون أن الكلاس الأب ليس له علاقه بالإبن حينها ،وسوف يحتوي على متغيرات مثل المؤشر NArrays<T,N-1>* ptrArray; والإبن ليس بحاجة له ،،

وعند انشاء الكائن بالبعد 1 قد تحصل مشكلة حيث أن أي انشاء لكائن subclass سوف يتم استدعاء الsuperclass مباشره ، وقد يتسبب هذا في مشكلة infnite recursion .. لم أجرب ولكنها قد تكون كذلك والله اعلم ...

انت خسران ايه يا محمد ، عملية copy & paste وينتهي الموضوع :D

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#19
اقتباس
انت خسران ايه يا محمد ، عملية copy & paste وينتهي الموضوع

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

شكرا اخ وجدى :)

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

مدونتي: C++ Tips and Tricks

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…