אוקיי
הסבר על מה שקורה: MatrixData - מכיל את נתוני המטריצה MatrixInterface - מחלקת אב שמייצגת ממשק כלשהו למידע ב-MatrixData. RotatedMatrixInt - דוגמה לממשק המתייחס למטריצה כאילו היא מסובבת יכולים כמובן להיות עוד ממשקים שעושים דברים אחרים, לדוגמה, מתייחסים למטריצה כאילו היא מורכבת רק מאפסים ואחדים וכו'. Matrix - מחלקת המטריצה למשתמש, אשר אך ורק דרכה עובדים. המשתמש מפעיל טרנספורמציות על המטריצה. המטריצה למעשה רק מחליפה את הממשק הפעיל כרגע. אם סובבתי את המטריצה ימינה, אזי הממשק יתחלף ל-RotatedMatrixInt עם זווית מסויימת. במקרה שלנו, קבעתי את הרביע הראשון עד הרביעי בעזרת המספרים 0 עד 3. רציתי להוסיף גם יישום שמאפשר לבצע כמה טרנספורמציות שונות אחת על השניה. זה דורש קצת יותר מלזכור את "הרביע האחרון". למעשה צריך לנהל מחסנית של טרנספורמציות. אתה מוזמן לנסות. במקרה כזה, אל תשכח שאת המחסנית צריך לרוקן מתישהו. *רק אז* רצוי להתחיל להזיז את האיברים "על אמת", ולקבל מטריצה בלי "הסטוריה", מחסנית ריקה, ולהמשיך משם. עיקרון זה הוא מאוד מקובל בתוכנות שמבצעות הרבה טרנספורמציות על מידע (לאו דווקא מטריצות ולאו דווקא סיבוב).
class MatrixData { int* m_arr; int m_width, m_height; public: MatrixData(int y, int x) { m_arr = new int[x*y]; m_width = x; m_height = y; } int Width() const { return m_width; } int Height() const { return m_height; } int& operator()(int y, int x) { return m_arr[y*m_width + x]; } }; class MatrixInterface { protected: MatrixData* m_data; public: MatrixInterface(MatrixData* pData) : m_data(pData) {} virtual int Width() const { return m_data->Width(); } virtual int Height() const { return m_data->Height(); } virtual int& operator()(int y, int x) { return (*m_data)(y,x); } }; class RotatedMatrixInt : public MatrixInterface { int m_nAngle; public: RotatedMatrixInt(MatrixData* pData, int angle) : MatrixInterface(pData), m_nAngle(angle) {} virtual int Width() const { return m_nAngle%2?m_data->Height():m_data->Width(); } virtual int Height() const { return m_nAngle%2?m_data->Width():m_data->Height(); } virtual int& operator()(int y, int x) { switch (m_nAngle) { case 1: return (*m_data)(Width()-x-1, y); case 2: return (*m_data)(Height()-y-1, Width()-x-1); case 3: return (*m_data)(x, Width()-y-1); default: return (*m_data)(y,x); } } }; class Matrix { MatrixInterface* m_intf; MatrixData* m_data; int m_nAngle; void ReplaceInterface(MatrixInterface* newIntf) { if (m_intf) delete m_intf; m_intf = newIntf; } public: Matrix(int y, int x) { m_data = new MatrixData(y,x); m_intf = new MatrixInterface(m_data); m_nAngle = 0; } int& operator()(int y, int x) { return (*m_intf)(y,x); } int Width() const { return m_intf->Width(); } int Height() const { return m_intf->Height(); } void RotateRight() { if (m_nAngle == 3) m_nAngle = -1; ReplaceInterface(new RotatedMatrixInt(m_data, ++m_nAngle)); } void RotateLeft() { if (m_nAngle == 0) m_nAngle = 4; ReplaceInterface(new RotatedMatrixInt(m_data, --m_nAngle)); } }; void main() { Matrix m(4,3); int i, j; for (i = 0; i < m.Height(); ++i) for (j = 0; j < m.Width(); ++j) m(i,j) = (i+1)*(j+1); for (i = 0; i < m.Height(); ++i) { for (j = 0; j < m.Width(); ++j) printf("%4u ", m(i,j)); printf("\n"); } m.RotateRight(); printf("\n\n"); for (i = 0; i < m.Height(); ++i) { for (j = 0; j < m.Width(); ++j) printf("%4u ", m(i,j)); printf("\n"); } }