MOOC清华《面向对象程序设计》第5章:填充数字矩阵-终极中文版 v 3.0(采用模板方法,并增加集中控制功能)

//main.cpp      
#include <iostream>   
#include <cstring>   
#include "Matrix.h"      
using namespace std;  

const int str_length = 7;//经测试,至少为7;印证了每个汉字占2个字节('\0'占一个字节)          
      
int main() {      
    int size;        
    char style[str_length];      
    char key_point[str_length];   
    cout << "请输入矩阵的边长 N: ";      
    cin >> size;     
    cout << "请输入填充方式(顺时针、逆时针、行优先、列优先): ";      
    cin >> style;      
    cout << "请输入从哪一个角开始填充(左上角、左下角、右上角、右下角): ";      
    cin >> key_point; 
	void fill_style(int size, char* str1, char* str2);
	fill_style(size, style, key_point);              
          
    return 0;      
}   

void fill_style(int size, char* str1, char* str2){              
 
    if(strcmp(str1, "顺时针") == 0){   
        ClockwiseMatrix obj(size);  
        if(strcmp(str2, "左上角") == 0){  
            obj.row = 0;      
            obj.col = -1;      
            obj.dir = 'R';           
    		obj.fill();      
    		cout << obj; 
        }      
        if(strcmp(str2, "右上角") == 0){  
            obj.row = -1;      
            obj.col = size - 1;      
            obj.dir = 'D';  
    		obj.fill();      
    		cout << obj; 
        }      
        if(strcmp(str2, "右下角") == 0){  
            obj.row = size - 1;      
            obj.col = size;      
            obj.dir = 'L';   
    		obj.fill();      
    		cout << obj;  
        }      
        if(strcmp(str2, "左下角") == 0){  
            obj.row = size;      
            obj.col = 0;      
            obj.dir = 'U';  
    		obj.fill();      
    		cout << obj; 
        }  
    }      
      
    if(strcmp(str1, "逆时针") == 0){   
        AnticlockMatrix obj(size);   
        if(strcmp(str2, "左上角") == 0){  
            obj.row = -1;      
            obj.col = 0;      
            obj.dir = 'D';          
    		obj.fill();      
    		cout << obj; 
        }     
        if(strcmp(str2, "左下角") == 0){  
            obj.row = size - 1;      
            obj.col = -1;      
            obj.dir = 'R';    
    		obj.fill();      
    		cout << obj;     
        }     
        if(strcmp(str2, "右下角") == 0){  
            obj.row = size;      
            obj.col = size - 1;      
            obj.dir = 'U';    
    		obj.fill();      
    		cout << obj;     
        }     
        if(strcmp(str2, "右上角") == 0){  
            obj.row = 0;      
            obj.col = size;      
            obj.dir = 'L';     
    		obj.fill();      
    		cout << obj;    
        }     
    }      
      
    if(strcmp(str1, "行优先") == 0){   
        RowFirstMatrix obj(size);  
        if(strcmp(str2, "左上角") == 0){  
            obj.row = 0;    
            obj.col = -1;    
            obj.dir = 'D';  
    		obj.fill();      
    		cout << obj;   
        }   
        if(strcmp(str2, "右上角") == 0){  
            obj.row = 0;    
            obj.col = size;    
            obj.dir = 'L';    
    		obj.fill();      
    		cout << obj;     
        }      
        if(strcmp(str2, "左下角") == 0){  
            obj.row = size - 1;    
            obj.col = -1;    
            obj.dir = 'R';       
    		obj.fill();      
    		cout << obj;  
        }    
        if(strcmp(str2, "右下角") == 0){  
            obj.row = size - 1;    
            obj.col = size;    
            obj.dir = 'U';       
    		obj.fill();      
    		cout << obj; 
        }         
    }    
      
    if(strcmp(str1, "列优先") == 0){    
        ColFirstMatrix obj(size);  
        if(strcmp(str2, "左上角") == 0){  
            obj.row = -1;    
            obj.col = 0;    
            obj.dir = 'D';      
    		obj.fill();      
    		cout << obj; 
        }    
        if(strcmp(str2, "右上角") == 0){  
            obj.row = -1;    
            obj.col = size - 1;    
            obj.dir = 'L';       
    		obj.fill();      
    		cout << obj; 
        }    
        if(strcmp(str2, "左下角") == 0){  
            obj.row = size;    
            obj.col = 0;    
            obj.dir = 'R';    
    		obj.fill();      
    		cout << obj; 
        }   
        if(strcmp(str2, "右下角") == 0){  
            obj.row = size;    
            obj.col = size - 1;    
            obj.dir = 'U';       
    		obj.fill();      
    		cout << obj; 
        }    
    }   
}   


//Matrix.h      
#ifndef Matrix_h      
#define Matrix_h      
      
#include <iostream>      
using namespace std;      
      
class Matrix{           
public:      
    int _size;//方阵的规模       
    int *_data;//数据空间      
    int row, col;      
    char dir;//用于顺时针、逆时针、行优先、列优先时的方向判定    
    Matrix(int size);      
    ~Matrix();      
    void fill();      
    virtual int findPosition() = 0;  
    int fill_style(char* str1, char* str2);      
    friend ostream& operator<< (ostream& out, const Matrix& m);       
};      
  
class ClockwiseMatrix:public Matrix{  
public:  
    using Matrix::Matrix;  
    int findPosition();//顺时针辅助函数   
};  
  
class AnticlockMatrix:public Matrix{  
public:  
    using Matrix::Matrix;  
    int findPosition();//逆时针辅助函数   
};  
  
class RowFirstMatrix:public Matrix{  
public:  
    using Matrix::Matrix;  
    int findPosition();//行优先辅助函数      
};  
  
class ColFirstMatrix:public Matrix{  
public:  
    using Matrix::Matrix;  
    int findPosition();//列优先辅助函数      
};  
      
#endif      

//Matrix.cpp      
#include <iostream>      
#include <cstring>      
#include "Matrix.h"      
using namespace std;      
      
Matrix::Matrix(int size): _size(size) {       
    _data = new int[size * size];      
    memset(_data, 0, sizeof(int) * _size * _size);      
}      
      
Matrix::~Matrix(){      
    delete _data;      
}      
      
ostream& operator<< (ostream& out, const Matrix& m){      
    for(int r = 0; r < m._size; r++){ //row      
        for(int c = 0; c < m._size; c++) //col      
            cout << *(m._data + r * m._size + c) << '\t';      
        cout << endl;      
    }      
}        
      
void Matrix::fill(){       
    for(int num = 1; num <= _size * _size; num++){      
        int pos = findPosition();      
        _data[pos] = num;      
    }      
}         

//ClockwiseMatrix.cpp  
#include <iostream>         
#include "Matrix.h"      
using namespace std;   
  
int ClockwiseMatrix::findPosition(){       
    switch(dir){      
        case 'D':      
            if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)      
                row++;      
            else{      
                dir = 'L'; // next direction      
                col--;      
            }      
            break;      
        case 'L':      
            if(col > 0 && _data[row * _size + col - 1] == 0)      
                col--;      
            else{      
                dir = 'U'; // next direction      
                row--;      
            }      
            break;      
        case 'U':      
            if(row > 0 && _data[(row - 1) * _size + col] == 0)      
                row--;      
            else{      
                dir = 'R'; // next direction      
                col++;      
            }      
            break;      
        case 'R':      
            if(col < _size - 1 && _data[row * _size + col + 1] == 0)      
                col++;      
            else{      
                dir = 'D'; // next direction      
                row++;      
            }      
            break;      
    }      
    return row * _size + col;      
}      

//AnticlockMatrix.cpp  
#include <iostream>         
#include "Matrix.h"      
using namespace std;   
  
int AnticlockMatrix::findPosition(){       
    switch(dir){      
        case 'D':      
            if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)      
                row++;      
            else{      
                dir = 'R'; // next direction      
                col++;      
            }      
            break;      
        case 'R':      
            if(col < _size - 1 && _data[row * _size + col + 1] == 0)      
                col++;      
            else{      
                dir = 'U'; // next direction      
                row--;      
            }      
            break;      
        case 'U':      
            if(row > 0 && _data[(row - 1) * _size + col] == 0)      
                row--;      
            else{      
                dir = 'L'; // next direction      
                col--;      
            }      
            break;      
        case 'L':      
            if(col > 0 && _data[row * _size + col - 1] == 0)      
                col--;      
            else{      
                dir = 'D'; // next direction      
                row++;      
            }      
            break;      
    }      
    return row * _size + col;      
}      

//RowFirstMatrix.cpp  
#include <iostream>         
#include "Matrix.h"      
using namespace std;   
  
int RowFirstMatrix::findPosition(){    
    switch(dir){    
        case 'D'://行优先且向右且向下填充(左上角)    
            if(col < _size - 1 && _data[row * _size + col + 1] == 0)    
                col++;    
            else    
                if(row < _size - 1){    
                    row++;    
                    col = 0;    
                }    
            break;    
        case 'L'://行优先且向左且向下填充(右上角)    
            if(col > 0 && _data[row * _size + col - 1] == 0)      
                col--;      
            else    
                if(row < _size - 1){    
                    row++;    
                    col = _size - 1;    
                }    
            break;    
        case 'R'://行优先且向右且向上填充(左下角)    
            if(col < _size - 1 && _data[row * _size + col + 1] == 0)     
                col++;    
            else    
                if(row > 0){    
                    row--;    
                    col = 0;    
                }    
            break;    
        case 'U'://行优先且向左且向上填充(右下角)    
            if(col > 0 && _data[row * _size + col - 1] == 0)      
                col--;     
            else    
                if(row > 0){    
                    row--;    
                    col = _size - 1;    
                }    
            break;    
    }    
    return row * _size + col;    
}    

//ColFirstMatrix.cpp  
#include <iostream>         
#include "Matrix.h"      
using namespace std;   
  
int ColFirstMatrix::findPosition(){    
    switch(dir){    
        case 'D'://列优先且向下且向右填充(左上角)    
            if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)      
                row++;    
            else    
                if(col < _size - 1){    
                    col++;    
                    row = 0;    
                }    
            break;    
        case 'L'://列优先且向下且向左填充(右上角)    
            if(row < _size - 1 && _data[(row + 1) * _size + col] == 0)      
                row++;      
            else    
                if(col > 0){    
                    col--;    
                    row = 0;    
                }    
            break;    
        case 'R'://列优先且向上且向右填充(左下角)    
            if(row > 0 && _data[(row - 1) * _size + col] == 0)      
                row--;     
            else    
                if(col < _size - 1){    
                    col++;    
                    row = _size - 1;    
                }    
            break;    
        case 'U'://列优先且向上且向左填充(右下角)    
            if(row > 0 && _data[(row - 1) * _size + col] == 0)      
                row--;    
            else    
                if(col > 0){    
                    col--;    
                    row = _size - 1;    
                }    
            break;    
    }    
    return row * _size + col;    
}    

全方位无死角测试:

【顺时针】






【逆时针】






【行优先】






【列优先】






调试成功的经验:
把之前Debug日志中的Style类换成main文件中一个普通函数,然后分别实例化四个派生类,分别传参数,分别调用填充函数fill()(同时自动调用各自的findPosition()),分别输出结果——一切搞定。


什么样的功能适合用派生类实现,什么样的功能适合用普通函数实现,什么样的功能适合放在main文件中……这些都是需要考虑的:既要全盘考虑各个功能、接口之间的关系,又要考虑每个功能、每个接口的实现细节。作为一个独立开发者、未来的创业公司CEO,务必有这种能力。


至于派生类与基类之间的构造函数和各个成员的调用关系,还需要在回顾代码的过程中仔细体会。已经得到的基本认识就是:派生类using基类的构造函数,若带参数,则直接初始化了基类的相应参数(比如_size)。如果这个参数是公有的,则派生类本身继承来的这个参数也得到了初始化;如果这个参数是私有的,则派生类并没有继承它,也就不存在初始化这个参数一说。而派生类的其他继承自基类的公有成员,若被赋值,则只停留在派生类这一级的成员,并不会“上传”至基类的成员。


最重要的一条经验还是:不要把两个平级的派生类搅和在一起,否则会跟goto语句一样地引起逻辑混乱,不易理解。所以说,虽然是面向对象程序设计了,但是依然要遵循流程化的设计思想,不同的流程分支互相不干涉,这样设计出的程序才既干净又清晰。所谓软件工程要力图避免的软件危机现象,我认为其实就是团队中不同的人之间在程序设计的逻辑思维上存在这样或那样的偏差,从而引起了混乱。用《人月神话》中的话说,就像一头巨兽掉进了泥潭,越挣扎陷得越深。从昨天中午到今天早上,我就感觉自己是那头巨兽。一个人独立编程都会出现软件危机的情况,多人尤其是很多人的时候当然更加容易出现。


作为一个计算机和软件的初学者,上述观点也许片面,但是是我的真实感受。希望今后继续提高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值