tm-blogs

Timothy Liu's blogs

View on GitHub
Back

Lecture

计算机程序设计基础 (2) 小班辅导 20230601


刘雪枫 - 无 92

Copyright (C) Timothy Liu 2023-2024

许可证:Creative Commons — 署名-相同方式共享 4.0 国际 — CC BY-SA 4.0

2023.06.01


目录

[TOC]

引(fei)言(hua)

我们先简单回顾一下程设(2)究竟要讲什么:一个是 C++,一个是面向对象。

C++

C++ 是一门支持面向对象特性的语言,支持多种编程范式(面向对象编程、面向过程编程、泛型编程、函数式编程、……)。被成为“C++ 之父”的 Bjarne Stroustrup 于 1979 年开始制作 C with class,后更名为 C++。下图即为传说中的发量惊人的“C++ 之父”——Bjarne Stroustrup

BS2018

C++ 目前由国际标准委员会 ISOWG21 工作组进行标准化。1998 年第一个 C++ 标准(称作 C++98)被发布。目前 C++ 每三年发布一次新标准(ISO 标准一般是十年,但由于语言出台新特性需要等十年过于久远,所以缩短为三年)。目前,C++ 标准历经沧桑已经或即将发布

发布年份 称呼 备注
史前时期 C with Classes / C++2.0 / 3.0、…… 1. 版本很多;2. 我们的程设比这个先进一点
1998 C++98 第一个 ISO C++ 标准,至今仍有市场
2003 C++03 C++98 的 bug 修复版本,改动不大,常不与 C++98 做特别区分
2011 C++11、C++0x 一次大的改动(一门新语言的诞生)
2014 C++14 给 C++11 打补丁的
2017 C++17 本来想搞大的,但是拉胯了
2020 C++20 一次大的改动(又一门新语言的诞生)
2023 C++23 给 C++20 打补丁的,马上要来了(将于 2023 年 12 月发布)
2026 C++26 ???

问:那咱们的程设是哪一个标准呢?

答:咱们的程设是微软(Microsoft)发布的 VS2008“标准”(

当然最接近的标准是 C++98 或 C++03

面向对象编程(OOP)

OOP 是一种编程范式,以类和对象作为编程的第一等公民。

需要注意的是,C++ 支持面向对象的特性,但 C++ 支持面向对象特性特定并不等于面向对象。面向对象是一种编程的范式,或者说是一种代码的架构,和语言无关,即使是 C 语言也可以进行面向对象编程,而 C++ 仅仅是从语法层面上为面向对象编程提供了便利,但使用 C++ 面向对象特性并不等于面向对象的程序设计。

2013 年与 2015 年考试试题讲解

注:大体上都是照着考题原带的答案抄的,但考题原带的答案并不完全正确,对有问题的答案,本文档给予了适当说明

不带 * 的是 2013 年试题,带 * 的是 2015 年试题

填空

填空题没什么好说的,背课件就完了(这里推荐 sjs 老师的课件,看起来相对比较规整)。

1

面向对象程序设计有四个主要特点,即抽象、封装、()和()。

继承;多态

如果是三个特点,可以不答”抽象“

2

非成员函数应声明为类的()函数才能访问这个类的 private 成员

友元

友元:非成员、类似于“白名单”

4

在用 class 定义一个类时,数据成员和成员函数的默认访问权限是()。

private / 私有

  • structpublic
  • 默认继承权限同理
  • structclass 除了默认的成员权限和继承权限之外是完全等价

4*

class B 中定义成员函数 int f1() 和数据成员 int a;如果将函数 f1() 定义成静态成员函数,则定义式为();如果将 a 定义为静态数据成员,并在类外对其初始化为 0,则该语句为()

static int f1();int B::a = 0;

实际上题目表述有误,static int f1(); 是声明而非定义;int B::a = 0;B::a 的定义;只有声明而无没有定义而使用会产生链接错误

const 修饰可以只有声明而没有定义而取其值,但不能取指针也不能取引用(链接错误),具体原因参见阅读材料 2 的关于 odr-use 的部分(但是这部分还没写,但愿暑假不会鸽 x)

10

用 new 申请某一个类的动态对象数组时,在该类中必须能够匹配到()的构造函数,否则应用程序会产生一个编译错误。

没有形参 / 缺省参数

原因是 C++03 及之前使用 new[] 时不能给初值

C++11 之后其实可以给。。。:int *a = new int[2] { 9, 8 };,但是没卵用 x

6*

有类 A,语句组 A a(1), b; b = a; 和语句 A a(1), b(a); 在生成对象 b 并用 a 赋初值时的差别是,后者(),而前者()

调用 b 的复制构造函数,用 a 复制构造 b;先调用 b 的默认构造函数,再使用 ab 赋值。

顾名思义,、、构造函数和复制构造函数都是在有新对象构造的时候才会调用。

复制构造函数:参数绝大多数情况下必须const 引用,极少数情况才会无 const。原因参见阅读材料 2

5

运算符重载函数可能是类的()函数,也可以是类的()函数,还可以是普通函数。

成员;友元

  • 举例 complex

这题确定不是废话么 x

zài zài zài(x

8

重载的运算符保持其原有的()、优先级和结合性不变

操作数个数

10*

运算符重载时需要保持运算符操作数的个数、运算符的执行()和()不变

结合性;优先级

3

派生类中的成员不能直接访问基类中的()成员

私有 / private

  • 继承时,三种访问权限的直观理解,及存在意义

    特殊用途:EBO、……

  • struct 默认是 public 继承

9*

公有继承下,派生类的成员函数可以直接访问基类的()成员,但不能直接访问基类的()成员

publicprotected / 公有和受保护的;private

此题原答案有误,第一个空没考虑 protected 成员

7*

虚函数通常在相应的成员函数前加上()关键字声明,此类函数的调用会延迟到()时再进行动态束定(绑定),没有声明为 virtual 的成员函数则在编译时进行静态束定(绑定)

virtual;运行

构造函数中不会呈现多态性。为什么?构造函数执行顺序。为什么是这个执行顺序?反过来行不行?

1*

C++ 引入了函数重载和虚函数。其用途分别用一句话概括:函数重载是();虚函数是()

通过静态束定,在编译时确定调用同名函数中的哪一个;通过动态束定,在程序运行时确定调用同名函数中的哪一个

7

含有纯虚函数的类称为()。

抽象类

9

在 C++类中,有一种不能定义对象的类,这样的类只能被继承,称之为(),定义该类至少具有一个()。

抽象类;纯虚函数

8*

包含纯虚函数的类被称为(),某类包含一个纯虚函数 int fun(),则该成员函数应声明为()

int fun() = 0;

注:程设课上讲到的纯虚函数不能有函数体的说法其实是有误的,纯虚函数也可以定义函数体,但考试就当作不能(

6

用流对象的成员函数控制输出格式时,用于设置字段宽度的流成员函数的名称是(),与之作用相同的控制符名称是()。

widthsetw

  • 只能死记硬背
  • 自定义流操纵算子

5*

在 C++ 程序中 cin 是在()中定义的();coutcerrclog 三者的相同点是()

iostream输入流对象(?);向标准输出设备输出

此题有误,cerrclog 其实是向标准错误设备输出,所以它们其实共同点只有它们都是输出,但是为了考试拿分就这么答吧

辨析 coutcerrclog 的区别:

  • cout:标准输出设备,有缓冲
  • clog:标准错误设备,有缓冲
  • cerr:标准错误设备,无缓冲

3*

C++ 程序中使用 using namespace std; 的原因是(),使用 #include <iomanip> 是因为()

太长了懒得打字,参见原题上的答案

2*

C++ 中类和类模板的关系可以表述为:类是类模板的(),类模板是类的()

实例;抽象(?)

编程填空

2013

1
virtual void show() const {
    cout << "Base" << endl;
}
virtual void show() const {	// virtual 可省
    cout << "Derived" << endl;
}

考察多态

原答案不加 const 也正确,但不够规范。原因参见阅读材料 2

2
counter operator+(counter c)
/* 或 */
counter operator+(const counter& c)
return counter(n + c.n);

原答案第二个空也正确

3
void show_time() const
cout << hour << ':' << minute << ':' << sec << endl;

原答案疑似 const 位置错误

4
ifstream in("test.txt");
/* 或 */
ifstream in("test.txt", ios::in);
cout << i << ':' << buf << endl;

对于 ifstream 来说,构造函数第二个参数默认是 ios::in

5
virtual void Area() = 0;

这次不能写成 Area() const,因为 Rectangle 类的 Area 是非 const 的!

Rectangle(double w, double h) : width(w), height(h) {}

原答案为 Rectangle(double w, double h) { width = w, height = h; } 也正确

补充

1
class People
{
public:
    People(int age) : m_age(age) {}
private:
    int m_age;
};

class Student : public People
{
public:
    Student(int age, int id) ______ {}
private:
    int m_id;
};

: People(age), m_id(id)

看程序写结果

面向对象程序设计(Optional)

面向对象程序设计原则(注意此处说的是面向对象,而非指 C++ 面向对象的语言特性):

下面着重说一下里氏替换原则。

里氏替换原则

里氏替换原则:派生类可以直接替换掉基类。即,任何一个派生类对象都“是”一个基类对象。这个“是”的含义代表,任何对基类对象的操作对派生类对象来说在逻辑上都成立。

反例 1

Line 继承 Point 不是一个好的设计。一个 Line 并不是一个 Point,不符合 LSP

sjs 课件 (6) 77 页

反例 2

下面所演示的 Square 继承 Rectangle 就不是一个好的设计:


class Rectangle {
public:
    Rectangle(int width, int height) : width(width), height(height) {}
    int getWidth() const { return width; }
    int getHeight() const { return height; }
    void setWidth(int newWidth) { width = newWidth; }
    void setHeight(int newHeight) { height = newHeight; }

private:
    int width;
    int height;
};

class Square : public Rectangle {
public:
    Square(int edge) : Rectangle(edge, edge) {}
    int getEdge() const { return Rectangle::getWidth(); }
    void setEdge(int newEdge) {
        Rectangle::setWidth(newEdge);
        Rectangle::setHeight(newEdge);
    }
};

确实我们在日常生活中都说“正方形是一个长方形”,但是在本代码中并不是这样——因为我们对 Square 暴露了公有接口 setWidthsetHeight。如果我们执行了:Square sq(10); sq.setWidth(88);,那么就出现了问题——这个正方形长等于宽的性质被打破。也就是说,正方形并不能完全替代长方形,并不满足长方形所能进行的全部操作!所以这种设计思路是不符合里氏替换原则的。

特别注意

里氏替换原则是面向对象的原则,而非 C++ 语法的规定。有一些情况,为了一些特殊的目的,会使用 C++ 语法上的“继承”,例如模板元编程、EBO,等等,都可能会使用 C++ 的继承语法。但这属于 C++ 语法的技巧,并不属于面向对象的程序设计范畴。

面向对象程序设计?

设想我们有一个场景,我们要把大象装入冰箱中。分几步呢?分三步:把冰箱门打开,把大象装进去,把冰箱门关上。

编译、链接、多文件(Optional)

Q & A

之前发的问卷,有些人问了一些问题

2023

qa2023

2022

Q:怎么才算,面向对象的程序设计呢?那种大厂的游戏开发也是用这种类和对象来编程的吗?

A:

  1. 面向对象程序设计思想通过我的一节课很难把它讲清楚,需要自己多阅读、尝试和练习
  2. 面向对象只是组织代码方式的一种,也是一种经典的、传统的编程范式。代码当然可以采用其他的编程范式来组织。但是至少,目前最主流的两个游戏引擎:Unity 和 UE(Unreal Engine),都是通过面向对象来组织的。不过面向对象也不是万能的,还是要看具体用途。

Q:可以加学长微信聊天吗?

A:可以,QQ 也行(x

阅读材料

由于课时原因,有很多有趣的内容我们都没有讲解。这些内容在程设的日常教学中已经涉及到,但是与考试关系不大。略去这些内容不会对我们的考试产生太大影响。有兴趣探索的同学可以阅读以下材料:

所有阅读材料均在 https://timothy-liuxf.github.io/tm-blogs/blogs/zh-CN/ 中可见。包括:

  1. 左值与右值
  2. 为什么 const 在 C++ 中是重要的
  3. 返回值优化

显然,目前我还没写完,先鸽一段时间(bushi

预祝同学们考试顺利(√) 祝同学们儿童节快乐(bushi

QR Code

请同学们填写反馈问卷,谢谢大家!

反馈问卷略。

参考文献