第5单元作业【4】 - 在线编程(难度:难)
温馨提示:
1.本次作业属于Online Judge题目,提交后由系统即时判分。
2.学生可以在作业截止时间之前不限次数提交答案,系统将取其中的最高分作为最终成绩。
在本单元作业【3】的基础上,增加Circle类
依照学术诚信条款,我保证此作业是本人独立完成的。
题目内容:
修改MyRectangle类:
-
增加公有 showScreen() 成员函数
1)该函数通过使用类内的screen_私有数据成员访问MyRectangle对象所保存的屏幕的信息
2)输出屏幕的宽和高,以空格分隔,然后换行
新增MyCircle类:
-
在MyCircle类中,增加表示三种颜色分量(Red、Green、Blue)的数据域成员;
-
在MyCircle类中,增加函数 setColor(int R, int G, int B);该函数接收三个参数,代表颜色中的Red、Green、Blue分量的大小,该函数将颜色保存在类的数据域成员中。
-
MyCircle类中增加一个私有的指向Screen类型的指针成员 screen_
-
MyCircle类的构造函数1接受3个整型参数和1个Screen*类型的参数
1) 按照顺序,整型参数分别为圆心的x、y坐标,以及圆的半径。
2)此处不检查坐标及半径的有效性
3)Screen*类型的参数指向一个已经存在的Screen对象,本构造函数将该Screen对象的地址存入私有数据成员 screen_ 中 -
MyCircle类的默认构造函数将圆心的坐标设置为(200,200),半径设置为100
-
MyCircle类的“构造函数1”与默认构造函数均将表示颜色的数据成员初始化为白色,也就是RGB三个颜色分量的值均为255
-
为MyCircle类添加拷贝构造函数
1)在拷贝构造函数的尾部添加输出语句,输出字符串“copy mycircle”并换行
2)思考:该拷贝构造函数的参数,应该是 MyCircle& 类型,还是 const MyCircle& 类型?这决定着本测试所给的主函数能否通过编译。
2)思考:该拷贝构造函数是否需要“深拷贝”? -
MyCircle类的所有非拷贝构造函数均应输出字符串“mycircle”并换行
-
MyCircle类中应提供setCenter(int x, int y)用于设置圆心坐标,提供setRadius(int r)用于设置圆的半径。函数的返回值自行确定。
-
在Draw()中用输出:
a. 圆心的x、y坐标以及半径(坐标值以及半径等3个数值间以1个空格分隔)然后换行;
b. 圆的颜色的RGB分量的值,用空格分隔开的三个整数,然后换行 -
增加公有 showScreen() 成员函数 (与MyRectangle类的函数相同)
1)该函数通过使用类内的screen_私有数据成员访问MyCircle对象所保存的屏幕的信息
2)输出屏幕的宽和高,以空格分隔,然后换行 -
MyCircle类中应提供setScreen(Screen& screen)用于设置该类的实例所对应的Screen对象(同MyRectangle类中的代码)1)即,setScreen函数会将引用参数 screen 这个对象的地址赋给MyCircle类中的私有成员 screen_2)要注意:私有成员 screen_ 是对象指针类型,而setScreen()的形式参数 screen 是对象引用类型3)所以,在setScreen()函数体内, 要取 screen 这个参数的地址,再将该地址赋值给私有成员 screen_4)函数返回值类型由你自己决定
-
以上所有换行均请使用std::endl
-
如有必要,则增加其他数据成员及函数成员
-
不要输出任何未要求输出的信息,尤其是不必要的“空格”,不然会导致测试例无法通过。
主函数如下(不可修改):
- int main() {
- int width, height;
- cin >> width >> height;
- int leftX, leftY, rightX, rightY;
- cin >> leftX >> leftY >> rightX >> rightY;
- int centerX, centerY, radius;
- cin >> centerX >> centerY >> radius;
- Screen *screen = Screen::getInstance(width, height);
- MyRectangle myRectangle(leftX, leftY, rightX, rightY, screen);
- myRectangle.setColor(0, 0, 0xff);
- myRectangle.showScreen();
- myRectangle.Draw();
- // 构造圆形对象数组
- //// 第一个元素使用匿名对象(调用带参构造函数)初始化
- //// 第二个元素使用匿名对象(调用默认构造函数)初始化
- MyCircle myCircles[2] = { MyCircle(centerX, centerY, radius, screen) };
- // 设置对象数组中第二个元素的属性。注意访问成员函数的不同方法
- (myCircles + 1)->setCenter(centerX+10, centerY+20);
- myCircles[1].setRadius(radius+30);
- (*(myCircles+1)).setColor(0x00, 0x00, 0x00);
- myCircles[1].setScreen(*screen);
- for(int i=0; i<=1; i++) {
- myCircles[i].showScreen();
- (myCircles+i)->Draw();
- }
- // 调用拷贝构造函数以myCircles数组中的第二个元素为模板创建新对象
- MyCircle yourCircle(myCircles[1]);
- yourCircle.showScreen();
- (&yourCircle)->Draw();
- screen->deleteInstance();
- #ifdef DEBUG
- std::cin.get();
- #endif
- return 0;
- }
输入格式:
首先输入空格分隔的屏幕宽度和高度
然后输入空格分隔的矩形的坐标(四个整数),代表【左上--右下】对角线上的两个坐标点
最后输入圆形的圆心坐标和半径
输出格式:
见输出样例。
不同的输入会导致不同的输出信息
输入样例:
800 600
50 50 400 300
500 200 100
输出样例:
enter screen
myrectangle
800 600
50 50 350 250
0 0 255
mycircle
mycircle
800 600
500 200 100
255 255 255
800 600
510 220 130
0 0 0
copy mycircle
800 600
510 220 130
0 0 0
leave screen
注意:输出样例的最后一行为空行,不可遗漏
#include <iostream> #include <string> using namespace std; class Screen { public: int getWidth(); int getHeight(); public: static Screen* getInstance(int width, int height);//3.在Screen类中,增加一个静态公有的 getInstance(int width, int height) 函数,该函数返回instance的值。两个参数均带有默认值,分别为 640 和 480 void deleteInstance();//2.在Screen类中,添加一个deleteInstance()函数 ~Screen();//1.为Screen类添加析构函数 private: int width_;//屏幕的宽 int height_;//屏幕的高 std::string enter;//1.在Screen类中,添加两个 string 类型的数据成员 enter 和 leave,并在构造函数中将他们分别初始化为字符串“enter screen”和“leave screen”(每个字符串中只有一个空格分隔两个单词) std::string leave;//1.在Screen类中,添加两个 string 类型的数据成员 enter 和 leave,并在构造函数中将他们分别初始化为字符串“enter screen”和“leave screen”(每个字符串中只有一个空格分隔两个单词) static Screen* instance;//2.在Screen类中,增加一个 Screen* 类型的静态的私有数据成员 instance; private: void exitWhenInvalidScreen(int width, int height);//检测屏幕的宽与高是否 符合逻辑 Screen(int width, int height);//将Screen类中的所有构造函数都变成 private 成员 }; int Screen::getWidth() { return width_; } int Screen::getHeight() { return height_; } Screen* Screen::getInstance(int width = 640, int height = 480)//3.在Screen类中,增加一个静态公有的 getInstance(int width, int height) 函数,该函数返回instance的值。两个参数均带有默认值,分别为 640 和 480 { //4.在getInstance函数中,判断instance的值 // 1) 若instance值为0(即“instance是一个空指针”) // a.以width和height作为构造函数的参数,使用new运算符创建一个Screen对象 // b.将新的Screen对象的地址保存在instance中; // 2) 若instance的值不为0(即instance指向一个Screen对象),则返回instance的值 if (!instance) { instance = new Screen(width, height); } return instance; } void Screen::deleteInstance()//2.在Screen类中,添加一个deleteInstance()函数 { delete instance;//功能:将getInstance()函数中申请的内存归还给操作系统。 instance = 0;//将数据成员instance设置为空指针 } Screen::~Screen()//1.为Screen类添加析构函数 { std::cout << leave << std::endl;//析构函数应首先输出数据成员leave的内容并换行(使用std::endl) } void Screen::exitWhenInvalidScreen(int width, int height)//检测屏幕的宽与高是否 符合逻辑 { if (width <= 0 || height <= 0)//宽度和高度必须大于0像素(不能等于0像素) { std::cout << "invalid screen size";//如果宽或者高不满足上述任一条件,则整个程序仅仅输出字符串"invalid screen size",然后退出程序 exit(0); } if (width > 1000 || height > 1000)//宽度和高度均不得大于1000像素(可以等于1000像素) { std::cout << "invalid screen size"; exit(0); } } Screen::Screen(int width, int height)//将Screen类中的所有构造函数都变成 private 成员 { //修改Screen类的构造函数 // 1) 删除Screen类的默认构造函数,只保留带参构造函数,并修改之使其能初始化数据成员 // 2) 删除第4单元作业的Screen类的所有构造函数中的【cout << "screen" << endl; 】语句 // 3) Screen类的所有构造函数【均应输出】数据成员enter中的字符串内容并换行(使用std::endl),但是【不再输出其它信息】 // 4) Screen类的构造函数仍然使用第四单元作业中所要求的exitWhenInvalidScreen函数检查屏幕宽和高的有效性。(可以直接复用第四单元作业的相关代码);该部分代码必须放在输出数据成员enter的代码之后 width_ = width; height_ = height; enter = "enter screen";//1.在Screen类中,添加两个 string 类型的数据成员 enter 和 leave,并在构造函数中将他们分别初始化为字符串“enter screen”和“leave screen”(每个字符串中只有一个空格分隔两个单词) leave = "leave screen";//1.在Screen类中,添加两个 string 类型的数据成员 enter 和 leave,并在构造函数中将他们分别初始化为字符串“enter screen”和“leave screen”(每个字符串中只有一个空格分隔两个单词) std::cout << enter << std::endl; exitWhenInvalidScreen(width, height);//检测屏幕的宽与高是否 符合逻辑 } class MyRectangle { private: int x1_, y1_, x2_, y2_; int R_;//1.在MyRectangle类中,添加与颜色相关的属性:增加表示三种颜色分量(红色,绿色,蓝色)的三个数据域成员; int G_; int B_; Screen* screen_; int getWidth() { return x2_ - x1_; } int getHeight() { return y2_ - y1_; } public: MyRectangle(int x1, int y1, int x2, int y2, Screen* screen) { x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2; screen_ = screen; R_ = 255;//5.MyRectangle类的默认构造函数和带参构造函数需要将表示颜色的数据成员初始化为白色,也就是RGB三个颜色分量的值均为255;拷贝构造函数则不必 G_ = 255; B_ = 255; cout << "myrectangle" << endl;//6.MyRectangle类的所有构造函数的末尾均应使用cout输出字符串“myrectangle”并换行(使用std::endl) } MyRectangle() { x1_ = y1_ = 10;//3.MyRectangle类的默认构造函数将矩形左上角顶点的坐标均设置为(10,10),将右下角顶点坐标设置为(100,100) x2_ = y2_ = 100; screen_ = 0; R_ = 255;//5.MyRectangle类的默认构造函数和带参构造函数需要将表示颜色的数据成员初始化为白色,也就是RGB三个颜色分量的值均为255;拷贝构造函数则不必 G_ = 255; B_ = 255; cout << "myrectangle" << endl;//6.MyRectangle类的所有构造函数的末尾均应使用cout输出字符串“myrectangle”并换行(使用std::endl) } void setCoordinations(int x1, int y1, int x2, int y2) { x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2; } void setScreen(Screen& screen) { screen_ = &screen; } void Draw() { //8.Draw()函数中,仅仅只包含如下代码: // a.用cout输出矩形的左上顶点的x、y坐标以及矩形的宽度和高度(坐标值以及宽高等4个数值间以1个空格分隔)然后换行(使用std::endl); // b.然后用cout输出矩形颜色的Red、Green、Blue分量的整数值(用十进制输出),用单个空格分隔开这三个整数,然后换行(使用std::endl) cout << x1_ << " " << y1_ << " " << this->getWidth() << " " << this->getHeight() << endl; std::cout << R_ << " " << G_ << " " << B_ << std::endl; } void setColor(int R, int G, int B)//2.在MyRectangle类中,增加函数 setColor(int R, int G, int B);该函数接收三个参数,代表颜色中的Red、Green、Blue分量的大小,该函数将颜色保存在类的数据域成员中。函数返回值自行定义 { R_ = R; G_ = G; B_ = B; } void showScreen() { //修改MyRectangle类: // 增加公有 showScreen() 成员函数 // 1)该函数通过使用类内的screen_私有数据成员访问MyRectangle对象所保存的屏幕的信息 // 2)输出屏幕的宽和高,以空格分隔,然后换行 std::cout << screen_->getWidth() << " " << screen_->getHeight() << std::endl; } }; class MyCircle { public: void setColor(int R, int G, int B);//2.在MyCircle类中,增加函数 setColor(int R, int G, int B);该函数接收三个参数,代表颜色中的Red、Green、Blue分量的大小,该函数将颜色保存在类的数据域成员中。 void setCenter(int x, int y);//9.MyCircle类中应提供setCenter(int x, int y)用于设置圆心坐标,提供setRadius(int r)用于设置圆的半径。函数的返回值自行确定。 void setRadius(int r);//9.MyCircle类中应提供setCenter(int x, int y)用于设置圆心坐标,提供setRadius(int r)用于设置圆的半径。函数的返回值自行确定。 void Draw(); void showScreen(); void setScreen(Screen& screen); MyCircle(int centerX, int centerY, int radius, Screen* screen);//构造函数1 MyCircle();//5.MyCircle类的默认构造函数将圆心的坐标设置为(200,200),半径设置为100 MyCircle(const MyCircle&);//拷贝构造函数 private: int Red_;//1.在MyCircle类中,增加表示三种颜色分量(Red、Green、Blue)的数据域成员; int Green_; int Blue_; Screen* screen_;//3.MyCircle类中增加一个私有的指向Screen类型的指针成员 screen_ int centerX_; int centerY_; int radius_; }; void MyCircle::setColor(int R, int G, int B)//2.在MyCircle类中,增加函数 setColor(int R, int G, int B);该函数接收三个参数,代表颜色中的Red、Green、Blue分量的大小,该函数将颜色保存在类的数据域成员中。 { Red_ = R; Green_ = G; Blue_ = B; } void MyCircle::setCenter(int x, int y)//9.MyCircle类中应提供setCenter(int x, int y)用于设置圆心坐标,提供setRadius(int r)用于设置圆的半径。函数的返回值自行确定。 { centerX_ = x; centerY_ = y; } void MyCircle::setRadius(int r)//9.MyCircle类中应提供setCenter(int x, int y)用于设置圆心坐标,提供setRadius(int r)用于设置圆的半径。函数的返回值自行确定。 { radius_ = r; } void MyCircle::Draw() { //10.在Draw()中用输出: //a.圆心的x、y坐标以及半径(坐标值以及半径等3个数值间以1个空格分隔)然后换行; // b.圆的颜色的RGB分量的值,用空格分隔开的三个整数,然后换行 std::cout << centerX_ << " " << centerY_ << " " << radius_ << std::endl; std::cout << Red_ << " " << Green_ << " " << Blue_ << std::endl; } void MyCircle::showScreen() { //11.增加公有 showScreen() 成员函数 (与MyRectangle类的函数相同) // 1)该函数通过使用类内的screen_私有数据成员访问MyCircle对象所保存的屏幕的信息 // 2)输出屏幕的宽和高,以空格分隔,然后换行 std::cout << screen_->getWidth() << " " << screen_->getHeight() << std::endl; } void MyCircle::setScreen(Screen& screen) { //12.MyCircle类中应提供setScreen(Screen& screen)用于设置该类的实例所对应的Screen对象(同MyRectangle类中的代码) // 1)即,setScreen函数会将引用参数 screen 这个对象的地址赋给MyCircle类中的私有成员 screen_ // 2)要注意:私有成员 screen_ 是对象指针类型,而setScreen()的形式参数 screen 是对象引用类型 // 3)所以,在setScreen()函数体内, 要取 screen 这个参数的地址,再将该地址赋值给私有成员 screen_ // 4)函数返回值类型由你自己决定 screen_ = &screen; } MyCircle::MyCircle(int centerX, int centerY, int radius, Screen* screen) { //4.MyCircle类的构造函数1接受3个整型参数和1个Screen*类型的参数 // 1) 按照顺序,整型参数分别为圆心的x、y坐标,以及圆的半径。 // 2)此处不检查坐标及半径的有效性 // 3)Screen*类型的参数指向一个已经存在的Screen对象,本构造函数将该Screen对象的地址存入私有数据成员 screen_ 中 centerX_ = centerX; centerY_ = centerY; radius_ = radius; screen_ = screen; Red_ = 255;//6.MyCircle类的“构造函数1”与默认构造函数均将表示颜色的数据成员初始化为白色,也就是RGB三个颜色分量的值均为255 Green_ = 255; Blue_ = 255; std::cout << "mycircle" << std::endl;//8.MyCircle类的所有非拷贝构造函数均应输出字符串“mycircle”并换行 } MyCircle::MyCircle()//5.MyCircle类的默认构造函数将圆心的坐标设置为(200,200),半径设置为100 { centerX_ = 200; centerY_ = 200; radius_ = 100; Red_ = 255;//6.MyCircle类的“构造函数1”与默认构造函数均将表示颜色的数据成员初始化为白色,也就是RGB三个颜色分量的值均为255 Green_ = 255; Blue_ = 255; std::cout << "mycircle" << std::endl;//8.MyCircle类的所有非拷贝构造函数均应输出字符串“mycircle”并换行 } MyCircle::MyCircle(const MyCircle&rCircle)//拷贝构造函数 { //7.为MyCircle类添加拷贝构造函数 // 1)在拷贝构造函数的尾部添加输出语句,输出字符串“copy mycircle”并换行 // 2)思考:该拷贝构造函数的参数,应该是 MyCircle& 类型,还是 const MyCircle& 类型?这决定着本测试所给的主函数能否通过编译。 // 2)思考:该拷贝构造函数是否需要“深拷贝”? centerX_ = rCircle.centerX_; centerY_ = rCircle.centerY_; radius_ = rCircle.radius_; Red_ = rCircle.Red_; Green_ = rCircle.Green_; Blue_ = rCircle.Blue_; screen_ = rCircle.screen_; std::cout << "copy mycircle" << std::endl; } Screen* Screen::instance;//8.不要忘记在类外对Screen类的所有静态成员进行初始化,否则编译器会报告链接出错。 int main() { int width, height; cin >> width >> height; int leftX, leftY, rightX, rightY; cin >> leftX >> leftY >> rightX >> rightY; int centerX, centerY, radius; cin >> centerX >> centerY >> radius; Screen *screen = Screen::getInstance(width, height); MyRectangle myRectangle(leftX, leftY, rightX, rightY, screen); myRectangle.setColor(0, 0, 0xff); myRectangle.showScreen(); myRectangle.Draw(); // 构造圆形对象数组 //// 第一个元素使用匿名对象(调用带参构造函数)初始化 //// 第二个元素使用匿名对象(调用默认构造函数)初始化 MyCircle myCircles[2] = { MyCircle(centerX, centerY, radius, screen) }; // 设置对象数组中第二个元素的属性。注意访问成员函数的不同方法 (myCircles + 1)->setCenter(centerX + 10, centerY + 20); myCircles[1].setRadius(radius + 30); (*(myCircles + 1)).setColor(0x00, 0x00, 0x00); myCircles[1].setScreen(*screen); for (int i = 0; i <= 1; i++) { myCircles[i].showScreen(); (myCircles + i)->Draw(); } // 调用拷贝构造函数以myCircles数组中的第二个元素为模板创建新对象 MyCircle yourCircle(myCircles[1]); yourCircle.showScreen(); (&yourCircle)->Draw(); screen->deleteInstance(); #ifdef DEBUG std::cin.get(); #endif return 0; }