password
type
Post
status
Published
date
Jan 8, 2023
slug
summary
我练功发自真心
tags
备考
category
课程笔记
icon
Mrs.Chu 2020级软卓试卷分析
第一部分——Find Error

知识点:常变量const
const定义的是常变量,常变量的值不能被更新。
错误为:
x+=y; //需要注意的是,题目要求指出的应该是报错的位置,所以指出const int x不满足标准答案。

知识点:参数列表的缺省参数、缺省值
带有默认值得缺省参数必须定义在参数列表的末尾。
错误为:
int f(double x,int i=0,char c)

知识点:命名空间
using namespace
语句是用来指定当前命名空间的,后面必须跟命名空间的名字,不能跟一个变量或者表达式。错误为:
using namespace a::x=1;
正确写法应该将命名空间的指定和变量赋值分开,可以是:
using namespace a; x = 1; //或者直接修改命名空间中的变量 a::x=1;

知识点:友元函数
友元函数不是类的成员函数
不应该使用 C::function 来定义友元函数
C C::operator+()....

知识点:虚函数和纯虚函数
//对于代码段中的 virtual int g()=0; //含义是 定义 g()为纯虚函数 纯虚函数的特性是必须要在派生类中重载才可以产生对象 //否则派生类仍然为抽象类
所以错误应该是:
Base a; //因为在没有重载纯虚函数g()的基础下,是没有办法声明Base对象的

知识点:类的默认访问限定符
由于Class没有声明访问限定符
所以变量x和成员函数setx()的访问限定符默认为private
所以外部函数f()无法访问setx()
错误为:
c1.setx(3);

知识点:模版的初始化
模版的参数必须要是常变量,也就是编译器已经明确知道值的变量。
所以,错误在于:
Array<double,a> ar; //原因:a不是常变量,无法作为模板参数进行初始化产生实例

知识点:构造函数
在基类Base中有构造函数Base(){};
但是派生类Sub中没有调用Base类中的构造函数,在C++中,这是不被允许的。
错误为:
Sub(int x1,char c1) {...};
正确的写法是:
Sub(int x1, char c1) : Base(x1) {...};
类的构造函数和析构函数都没有返回值,所以在定义构造函数的时候,不允许在构造函数前设置返回值类型,否则,编译器会报错。例如:
Class Base{ void Base(){};//错误的 × ~Base(){}; }

知识点:静态函数
因为 m() 不是静态函数,因此不能使用类名来调用它。相反,必须使用一个实例来调用它,如 c1.m()
错误为:
C::m();
C++中的静态关键词static:静态成员函数可以通过C::f()来访问,否则需要实例化访问。

知识点:访问限定符
子类无法访问父类的私有成员
错误为:
return x;
第二部分 Write Output
1
#include <iostream> using namespace std; void func(int x, int& y, int *jia){ y *= x + 2; *jia = x + y; } int main( ){ int i = 10, j = 4, x1 = 1; func(i, j, &x1); cout << i << "," << j << "," << x1 << endl; return 0; }
知识点:函数的形参传递,值传递,引用传递,指针传递
10,48,58
2
#include <iostream> using namespace std; class Point { private: int x, y; public: Point(int i, int j) { x = i; y = j; } void Print() { cout << '(' << x << ','<< y << ')' << endl; } void operator += (Point p) { x += p.x; y += p.y; } void operator -= (Point p) { x -= p.x; y -= p.y; } }; int main() { Point P1(9, 8), P2(4, 6); P1.Print(); P2.Print(); P1 += P2; P1.Print(); P2 -= P1; P2.Print(); return 0; }
知识点:运算符重载
(9,8) (4,6) (13,14) (-9,-8)//注意 P1的值已被更改
3
#include <iostream> using namespace std; class A { static int obj_count; public: A() { obj_count++; } ~A() { obj_count--; } int get_num_of_objects() { return obj_count; } }; int A::obj_count = 0; A a;//在声明对象a 作用范围为global int main() { A b, *p, *q;//声明一个对象b 作用范围是main函数内 p = new A;//在p所指向的区域创建一个A类对象 q = new A[5];//在q所指向的区域创建5个连续的A类对象 cout << a. get_num_of_objects() << '\t'; //此时,对象应该有:a,b,p(1),q(5) 共计8个 delete []q; //删除了q所指向的q(5)对象 cout << p->get_num_of_objects() << '\t'; //此时,对象应该有a,b,p(1) 共计3个 for(int i = 0; i < 2; i++) { A c; cout << c.get_num_of_objects() << '\t'; //此时,对象应该有a,b,c,p(1) 共计4个 } //注意,在循环括号内实例化的对象,在括号外被释放 //此时的对象为a,b,p(1) 共计3个 delete p; //删除p(1) cout << b.get_num_of_objects() << endl; //此时的对象为a,b 共计2个 return 0; }
知识点:静态数据成员—对象计数器
循环中的对象作用域仅存在于循环括号内,离开循环即释放。
8 3 4 4 2
4
#include <iostream> using namespace std; int main() { try { int a = 9; throw a;//此处,将变量a抛出 其余try内代码均不继续执行 float f = 0.5F; throw f; } catch (float k) { cout << "Exception occured here -- float!\n"; } catch (int k) {//a在这里被catch接收,然后try结束 cout << "Exception occured here -- int!\n"; } cout << "Succeed!\n"; return 0; }
知识点:异常处理 throw 和 catch
Exception occured here -- int! Succeed!
5
#include <iostream> using namespace std; class BASE{ protected: int id; public: BASE() : id(0) {} int update(int n) { id += n; return id; } virtual void hello(){ cout << "BASE" << endl; } }; class DERIVED : public BASE { public: DERIVED () { id = 1;} int update(int n) { id += 2*n; return id;} void hello() { cout << "DERIVED " << endl; } }; int main () { BASE* objs[2]; objs[0] = new BASE(); objs[1] = new DERIVED (); for(int i=0; i<2; i++) { objs[i]->hello(); cout << objs[i]->update(10) << endl; } return 0; }
知识点:基类和派生类
在数组 objs 中,objs[0] 和 objs[1] 存储的都是指向基类 BASE 的指针,即使 objs[1] 实际上指向的是 DERIVED 类的对象。
当调用 objs[1]->update(10) 时,由于它是一个基类指针,所以它会调用基类的 update 函数,而不是派生类的 update 函数。因此,结果是 11 而不是 21。
如果希望在多态情况下调用派生类的 update 函数,需要在基类中将 update 函数声明为虚函数,然后在派生类中重新定义它。
BASE 10 DERIVED 11
第三部分 Analysis and Design
1

Animal Eagle Elephant Shark Object Telephone Television Camera Class Animals{} Class Eagle:public Animals{} Class Elephant:public Animals{} ....下略
2
Please define a class DoubleValue that wraps a value of primitive type
double and satisfies the following requirements:
(1) it has a default constructor which sets the value to 0.0;
(2) it has a constructor with one argument of type double that is wrapped;
(3) by overloading the operator “==”, it can compare this object against another specified DoubleValue object, and return true if and only if both DoubleValue
represent the same double value;
(4) it can return a string representation of the wrapped double value;
(5) it can return the value of this DoubleValue as an int type after a narrowing
primitive conversion.
知识点:构造函数、函数过载、运算符重载、强制转换
#include <string> #include <iostream> using namespace std; class DoubleValue { private: double a; public: DoubleValue()//1 { a=0.0; } DoubleValue(double ta) {//2 a = ta; } bool operator==(DoubleValue d)//3 { if(a==d.geta()) { return true; } return false; } double geta() { return a; } std::string toString() const//4 { return std::to_string(a); //C++11标准后合法 }; int toInt()//5 { return (int)a; } }; int main () { return 0; }
第四部分 Programming
1
Implement a class Integer that can substitute the basic int type in C++. The
interfaces of the class Integer SHOULD output the messages or input data
shown in the following program’s comments.
int main() { Integer a, b = 10, c(b); cout << "a=" << a << endl; // Display: a=0 cout << "b=" << b << endl; // Display: b=10 cout << "c=" << c << endl; // Display: c=10 cin >> c; // input 2 from keyboard cout << "c=" << c << endl; // Display: c=2 c = b + 90; cout << "b=" << b << " c=" << c << endl; // Display: b=10 c=100 a = b - 100; cout << "a=" << a << " b=" << b << endl; // Display: a=-90 b=10 c = a / b; cout << "a=" << a << " b=" << b << " c=" << c << endl; //Display: a=-90 b=10 c=-9 c = b *= a; cout << "a=" << a << " b=" << b << " c=" << c << endl; //Display: a=-90 b=-900 c=-900 return 0; } ***Hint:*** Operator “<<” and “>>” can be overloaded as followings: ostream& operator<< ( ostream& out, Integer& I ) { out << I.value; return out; }
知识点:运算符重载
值得注意的是,对于 操作符 “<<”和“>>”的 重定义 必须通过 friend来进行 因为这些操作服属于ostream类的私有成员,必须通过声明友元关系的方式来获取访问权限。
在Integer类内,对于<<和>>运算符的定义特别声明了friend友元关系,这是为了让运算符与Integer建立友元关系,方便它访问Integer的私有成员。
class Integer { private: int v; public: Integer() { v=0; }; Integer(int tv) { v=tv; }; Integer operator=(const Integer& atr) { v=atr.v; }; friend std::ostream& operator<<(std::ostream& out,const Integer i) { out<<i.v; return out; }; friend std::istream& operator>>(std::istream& in,Integer& i) { in>>i.v; return in; }; Integer operator+(const Integer& second) { return Integer(v+second.v); }; Integer operator-(const Integer& second) { return Integer(v-second.v); }; Integer operator/(const Integer& second) { return Integer(v/second.v); }; Integer operator*=(const Integer& second) { v*=second.v; return *this; }; };
2
According to the main function and the output below, implement a class
hierarchy with Sequence as the base class with a method print which output the
value of a data member named number. Derived classes are Increment, Power
and Decrement.
int main() { Sequence *spi = new Increment(2); Sequence *spp = new Power(3); Sequence *spd = new Decrement(4); for(int i = 0; i < 3; i++) { spi->print(); spp->print(); spd->print(); cout<<endl; } return 0; }

知识点:派生类重写基类虚函数,构造函数的参数读取和重写,override关键字的使用
#include <iostream> using namespace std; class Sequence { protected: int number_; public: Sequence(int number):number_(number){} virtual void print() { printf("%d ",number_); } }; class Increment:public Sequence { public: Increment(int number):Sequence(number){} void print() { printf("%d ",number_); number_++; } }; class Power:public Sequence { public: Power(int number):Sequence(number){} void print() { printf("%d ",number_); number_*=number_; } }; class Decrement:public Sequence { public: Decrement(int number):Sequence(number){} void print() { printf("%d",number_); number_--; } }; int main() { Sequence *spi = new Increment(2); Sequence *spp = new Power(3); Sequence *spd = new Decrement(4); for(int i = 0; i < 3; i++) { spi->print(); spp->print(); spd->print(); cout<<endl; } return 0; }
需要注意的几个知识点:
- 隐式类型转换——二义性 在过载函数来实现多种类型数据读入的时候,可能存在二义性,会产生error,例如:
void print(double x); void print(long x); print(1);//error 由于转换的二义性
- 基类虚函数和派生类重载,构造函数 派生类的构造函数必须调用基类的构造函数 如果需要在派生类中重载函数,那么必须保证基类内的同名函数为虚函数 纯虚函数不能被实例化,必须要在派生类中重载
Class Base { public: Base(); .... virtual void func(){}; } Class D:public Base { D():Base(){};//调用基类构造函数 void func(){};//重载虚函数 }
- 重载(Override)和过载(Overload) 重载:方法的覆盖 子类同名同参覆盖基类 过载:方法的多态 同名不同参不同返回值
- 静态数据成员、静态成员函数和只读成员函数 在类的定义中,可以利用static关键字来使类的成员变成静态成员,这些静态成员只能通过类的访问符::直接访问。 而只读成员函数则可以确保该函数不会对数据成员进行修改。
Class C { private: static int count;//静态数据成员 int a; public: C(){}; ~C(){}; void func()const{};//只读成员函数 }
- 友元关系 友元关系是单向的,并且不具备传递性。例如:在A类中声明B是A的友元类,那么B有权访问A中的所有成员,但是A并不能访问B的所有成员。 函数func一旦成为类C的友元函数,就可以调用C的所有成员。
#include <iostream> using namespace std; class A { private: int x; public: A(int x1):x(x1){} friend class B; }; class B { private: int y; public: B(int y1):y(y1){} void func(A& a) { printf("%d",a.x); } }; int main() { // A a=A(2); // B b=B(3); A a(2); B b(3); b.func(a); return 0; }
后记
期末考试结束,OOP成为了我排名最高的科目。
感谢褚华老师和小虎老师,也感谢认真复习的自己。
感谢看到这的你们,希望这篇文章对你有帮助,祝你前程似锦 🥳
- Author:KrystalRay
- URL:https://krystalray.blog/article/0307cfcd-0f99-4355-b86f-230c58c819fb
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!