如何教授面向对象编程 - 有什么好的起点吗?

16

我在高中、计算机培训机构等地教授C++已经有大约两年了。在教授变量、数组、结构体、函数等基础知识之后,我总是会以传统的例子来开始面向对象的实例部分,比如这个:

class Person {
public:

 Person();
 ~Person();
 char* getFirstName(); //we can use std::string instead of char* in optimization part
 char* getLastName();
 char* getFullName();
 int getAge();
 bool getGender();
 void printFullProfile();

 void setFirstName(char*);
 void setLastName(char*);
 void setAge(unsigned int); 
 void setGender(bool);
 void setGender(char);//f for female, m for male.

private:
 char* first_name; //or std::string but i prefer to use pointers in the beginning.
 char* last_name;
 unsigned int age;
 bool gender; //ladies 1(st) , male 0
}

然后完善这个Person类,教授新的知识,例如为什么getter和setter方法是有害的以及通过创建其他类(例如Student、Employee、Moderator等)避免访问器、继承、多态等必要的OOP技能和概念。

[编辑]: 并使这些类对解决编程问题有用。 (如为每个Employee对象计算工资,学生平均分数等)

另一些基本示例是Vehicle类、Shape类等。

我想知道关于如何(只是)开始一个OOP课堂的你的想法。

期待着您的好点子。


8
对于你的例子,我有几条建议:1. 在使用C++时,我几乎从不鼓励使用char*——而是使用std::string;2. 没有必要为类的每个成员都编写setter函数(这很重要,可以教授封装的含义)。 - amit kumar
3
在我看来,C++不适合教授面向对象编程的原则,因为它的很多基本特性并不真正符合面向对象的思想,例如模板。话虽如此,我认为没有完美的面向对象编程教学语言存在 :-( - anon
2
记住,当与新手打交道时,最好使用类内的std::string而不是char *。这将节省您一些时间和烦恼,因为您无需解释内存分配、内存所有权和智能指针等问题。 - Thomas Matthews
4
小建议:不要使用缩写的字段和函数名。用"fname"代替"firstName"有什么好处呢?"firstName"一眼就能看懂,而且不会让新手想知道为什么到处都是奇怪的缩写。 - Matthew Olenik
8
我真的不喜欢使用布尔值来代表性别。即使男性有那个“额外的位”。 - Uri
显示剩余5条评论
9个回答

13

我建议从 CRC 卡片开始,不用写代码让班级角色扮演打出真正的面向对象设计。在这里,您可以介绍单一职责原则、谈论 has-a vs is-a 和继承、封装等概念。我遇到过太多不了解面向对象编程的程序员,他们仍在使用 C++、C#、Java 或 Delphi。

[编辑] 之后,您可能想将基于类的对象与 JavaScript(或 Self)和基于原型的面向对象进行比较,以探讨不同的分类方式。


+1个好建议。但我不会从代码开始我的课堂。我编辑了我的问题。谢谢。 - Michel Gokan Khan
我最近尝试了你的解决方案,对学生来说非常有趣,我意识到他们在面向对象编程的概念上比实现更困难。因此,CRC卡片是个好东西 :) - Michel Gokan Khan
正如@justsomebody在他的回答中提到的那样,我不会使用C++来教授面向对象编程,Java是我的首选语言。 - Michel Gokan Khan

7
正如其他人所建议的那样,使用真实世界的例子来解释事物;例如一个 车辆类(Vehicle class)和一个卡车类(Truck class)来进行继承。但这里有一个重要的部分:一旦他们理解了真实世界的例子,他们需要看到与程序相关的例子,然后才能真正理解为什么它对编程很重要。
我见过很多糟糕的C++代码,这不仅仅是因为那些不理解概念的人。我见过很多知道什么是对象,并能完美地解释多态性和所有技术面向对象编程术语的编码人员。但是如果他们不知道何时使用它,他们将永远无法充分利用它。我知道,因为我自己也是这样。我在高中读了一本面向对象编程的书,解释了所有概念,但我花了好几年才真正使用它们,因为我没有看到它们何时会实际有益于我的代码。尝试给出编程作业,其中不使用面向对象编程将更具挑战性。学生们自然会采取更简单的方法并开始理解。做是学习的最佳方式。
您可以拥有一个链表类(linked list class),并要求他们通过编写自己的 push/pop,enqueue/dequeue 方法来继承它以创建栈(stack)或队列(queue)。 或者制作一个二叉树类(binary tree class),并要求他们通过覆盖插入方法来将其转化为二叉搜索树。让他们使用动态内存,这样他们就可以看到为什么 [copy] 构造函数/析构函数很重要了。让他们编写一个定时器类(timer class),将时间存储为秒,但使用 getter/setter 自动转换成/从分钟或小时。
我不知道您的学生是否从一开始就使用 char 数组或 std::string。让他们两个都使用。当他们理解了字符数组的困难之处,他们就会更加欣赏字符串类,并理解类的重点是抽象化,而不仅仅是代码组织。如果您的学生曾经问过关于代码组织的问题,并且不确定特定数据或方法应该放在哪里,请记住这句话:
“事实上,我会断言,一个糟糕的程序员和一个优秀的程序员之间的区别在于他是否认为他的代码或数据结构更重要。糟糕的程序员担心代码,而好的程序员担心数据结构及其关系。”-Linus Torvalds

6
开始时要避免使用带有getter和setter的类。面向对象编程的一个主要承诺是“数据和程序一起运行”。它旨在解决过程式程序中长期存在的问题:对数据结构的更改在一个位置上产生的波动会随着数据的流动而远至整个程序。面向对象编程通过确保数据“停留在原地”来解决这个问题。getter和setter只是绕过面向对象编程的机制(数据在a->setX(y->getX())中传递),最终导致大量样板文件。
此外,不要使用C++来教授面向对象编程。使用专门为面向对象编程设计的语言。这种语言具有真正的封装性(对私有成员的更改不需要重新编译客户端代码),并统一对待所有类型(例如字符串字面量是一等公民对象)。

我在我的问题中忘记了一些东西(已编辑!)。我同意“不要使用C ++教授OOP”的部分,但是我可以在C ++课程中教Java或Python吗? - Michel Gokan Khan
你可能可以做Smalltalk。 - Stephan Eggermont
@Stephan Eggermont... Smalltalk是一种纯面向对象的语言,但我付费学习了C++ :D - Michel Gokan Khan
3
在这种情况下,不要教授面向对象编程。C++是一种糟糕的语言,除了过程式编程之外,可能不适合任何范例。教他们如何将在其他更清晰的语言学到的内容转化为C++语言。 - just somebody
避免使用getter和setter方法,如果你发现自己在这样做,就使用一个struct并放弃你有一个面向对象编程意义上的对象的虚假假象。 - Crowman

4
我不会选择C++来教授面向对象编程,因为C++并不是一种优雅的语言,而且在C++中面向对象编程有些奇怪。我更喜欢Java、Scala或者Python,Python是一种很好的教学语言。我的首选是Scala,因为它有很强的概念。例如,没有静态成员破坏了oop。不要忘记,如果编程有趣,教学效果会更好(C++不太有趣)。
我将涵盖以下内容:
- 面向对象编程的目标是什么? - 继承和接口的多态性 - 对象的责任 - 封装 - 对象之间的消息传递

2
@deamon 我同意你的观点。C++ 不适合作为教授面向对象编程的入门语言,但在 C++ 课堂上我别无选择。我能否在 C++ 课堂上教授 Java 或 Python 呢?我认为不行... - Michel Gokan Khan

3
这些内容与编程有何关联?告诉别人“你可以使用类来模拟物理对象,比如人”有什么好处?
这与他们想要学习的编程有什么关系?
用这种方式“教授”面向对象编程毫无意义,对于那些不熟悉面向对象编程概念的人是完全无用的。
如果您想教授面向对象编程,请展示一些在编程中有用的东西。面向对象编程的概念,例如类如何帮助解决实际编程问题?它们是否提供比以前使用的更清洁的解决方案?
接受“我们可能会有一个名为Person的类”的抽象事实很容易,也很容易接受“我们可以从这个Person类派生出更专业的人员类,比如清洁工或儿童或妇女”。缺少的是任何关于这在编程中如何有用的线索。继承如何有用地解决编程问题?多态性有什么用处?为什么我们关心数据隐藏?
至于你具体的例子,它给我们带来了什么好处?这只是一组getter和setter。几乎没有数据隐藏。没有抽象概念。这只是一个额外的代码,可以让我们一直以来所做的事情更加复杂。如果您无法编写一个好的类,那么您有资格教授吗?
此外,请使用std::string代替char*。是的,这意味着您必须告诉学生“std::string是字符串”,但至少您不必拥有所有繁琐和嘈杂的char指针管理。让您的代码保持干净,没有不需要的噪音。

1
谢谢@jalf。我在我的问题中忘记了一些东西,所以刚刚编辑了它。“就此而言,你的具体示例给我们带来了什么?”你提出的示例是什么?这就是我想知道的。 - Michel Gokan Khan
1
我在一年多之后再次检查了我的问题。但是你没有回复。你有什么建议的“现实世界”例子吗?一个我们可以称之为“好类”的类?让我们知道。 - Michel Gokan Khan

2
随着当今编程世界中接口的重要性日益增加,我建议您集中关注您的类执行的操作(行为),而不是它的字段和属性。这有助于强化“是一个”思想的概念(也称为里氏替换原则)。

1
对象由状态和行为组成。 - deamon
当然会有影响。但是,我见过太多看起来像赞美实体关系图的类设计。许多类最终拥有大量字段和几乎没有方法。在这一点上将它们应用于MVC平台等是相当具有挑战性的。 - Mike Hanson

1

正如我们所知,面向对象的概念非常贴近人类,因此当我开始使用面向对象的概念时,我总是给出实时的例子,这会产生很大的差异... 例如... -- 多态性:多态性的实时例子是“我”自己。看,只有一个人是我,但我有不同的角色,比如当我在家里时,我是父亲和母亲的儿子;当我在学校时,我是老师;当我在场地上时,我是一名运动员...... 看到只有一个人,即我,但我有不同的角色...... 即多态性

-- 抽象:我是一名教师,你们(学生)对我的教学感兴趣,而不是我为了收集这些数据做了什么以及我昨晚做了什么。即抽象避免向用户提供不必要的东西。


1
当我教授面向对象编程时,我尽量不从代码开始,而是从概念、思想和原因开始。这里是我曾经写过的面向对象介绍,我用它来进行教学。原文来自瑞典网页,这里提供了谷歌翻译的可怕版本

0
如果时间允许且学生渴望并能够学习,你可以教他们编写简单的GUI程序,构建GUI也是面向对象编程(OOP)所擅长的领域。
Qt是一款设计良好的C++工具,非常适合这项任务。在看到真实世界的例子之前,学生无法欣赏继承和虚函数。

1
@Michel 是的。在教授了一些基本概念后,您可以使用简单的GUI程序来说明OOP的风格和功能。我建议使用Qt,我们大学C++课程中1/4的OOP部分都使用Qt。而且学生们很喜欢这一部分 :) - Yin Zhu
我同意“教授一些基本概念后”部分。我也同意Qt部分。 - Michel Gokan Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接