C++面向对象程序设计-北京大学-郭炜【课程笔记(二)】
课程链接:程序设计与算法(三)C++面向对象程序设计 北京大学 郭炜
课程PPT:github提供的对应课程PPT
1、结构化程序设计
结构化程序设计的不足
- 结构化程序设计中,函数和其所操作的数据结构,没有直观的联系。
- 随着程序规模的增加,程序逐渐难以理解,很难一下子看出来:
-
- 某个函数结构到底有哪些函数可以对他进行操作?
-
- 某个函数到底是用来操作哪些数据结构的?
-
- 任何两个函数之间存在怎样的低哦啊用关系?
-
- 结构化程序设计没有“封装”和“隐藏”的概念。要访问某个数据结构中的某个变量,就可以直接访问,那么当该变量的定义有改动的时候,就要把所有访问该变量的语句找出来修改,十分不利于程序的维护、扩充。
-
- 难以查错,当某个数据结构的值不正确时,难以找出到底是哪个函数导致的。
-
- 结构化程序设计中,随着程序规模的扩大,由于程序大量函数、变量之间的关系错综复杂,要抽取这部分代码,变得十分困难(无法重用)。
2、面向对象的程序设计
2.1、面向对象的程序设计
面向对象的程序模式:(如下图所示)
2.2、从客观事物抽象出类
- 将长、宽变量和设置长、宽,求面积,以及求周长的三个函数“封装”在一起,就能形成一个‘矩形类’。
- 长、宽变量成为该“矩形类”的
“成员变量”
,三个函数成为该类的“成员函数”
。成员变量和成员函数统称为类的成员。
代码:
#include <iostream>
class CRectangle
{
public:
int w, h; // 成员变量
// 三个成员函数
int Area() {
return w * h;
}
int Perimeter() {
return 2 * (w + h);
}
void Init(int w_, int h_) {
w = w_; h = h_;
}
}; //必须有分号
int main()
{
int w,h;
CRectangle r; // r是一个对象
std::cout << "请输入w和h"<<std::endl;
std::cin >> w >> h;
r.Init(w, h);
std::cout << r.Area() << std::endl << r.Perimeter();
return 0;
}
//OUT:
请输入w和h
1
3
面积 = 3; 周长 = 8
2.3、对象的内存分配
2.4、对象之间的运算
和结构变量一样,对象之间可以用 “=” 进行赋值,但是不能用“==”,“!=”,“<”,“>=“,”<=“
,进行比较,除非这些运算符经过了“重载”。
2.5、使用类的成员变量和成员函数
用法1:对象名.成员名
CRectangle r1, r2;
r1.w = 5;
r2.Init(5, 4);
Init函数作用在r2上,即Init函数执行期间访问的w和h是属于r2这个对象的,执行r2.Init不会影响到r1。
用法2:指针->成员名
CRectangle r1,r2;
CRectangle * p1 = & r1;
CRectangle * p2 = & r2;
p1->w = 5;
p2->Init(5,4); //Init作用在p2指向的对象上
用法3:引用.成员名
CRectangle r2;
CRectangle & rr = r2;
rr.w = 5;
rr.Init(5,4); // rr的值变了,r2的值也会随着改变
void PrintRectangle(CRectangle & r)
{
cout << r.Area() << "," << r.Perimeter();
}
CRectangle r3;
r3.Init(5,4);
printRectangle(r3);
2.6、类成员的可访问范围
2.6.1、代码实例
#include <iostream>
#include <stdio.h>
// #include <string.h>
class CEmployee {
private:
char szName[30]; //名字
public :
int salary; //工资
void setName(char * name);
void getName(char * name);
void averageSalary(CEmployee e1,CEmployee e2);
};
void CEmployee::setName( char * name) {
strcpy(szName, name); //ok
}
void CEmployee::getName( char * name) {
strcpy(name, szName); //ok
}
void CEmployee::averageSalary(CEmployee e1,CEmployee e2){
salary = (e1.salary + e2.salary )/2;
}
int main(){
CEmployee e;
// strcpy(e.szName,"Tom1234567889"); //编译错, 不能访问私有成员
e.setName("Tom"); // ok
e.salary = 5000; //ok
return 0;
}
知识点扩充:C语言中字符串之间的比较【char*】/【string】
2.6.2、private的意义(隐藏的作用)
2.6.3、成员函数的重载及参数缺省
- 成员函数也可以重载
- 成员函数可以带缺省参数
- 案例如下:
#include <iostream>
class Location {
private:
int x, y;
public:
void init(int x = 0, int y = 0);
// 两个valueX是函数重载关系
void valueX(int val) { x = val; }
int valueX() { return x; }
};
int main() {
Location A, B;
A.init(5);
A.valueX(6);
std::cout << A.valueX() ;
return 0;
}
void Location::init(int x, int y)
{
x = x;
y = y;
}
// OUT
6
注意!!!
使用缺省参数需要注意避免有函数重载时的二义性
class Location {
private:
int x, y;
public:
void init(int x = 0, int y = 0);
两个valueX是函数重载关系
(这里存在二义性)
void valueX(int val = 0) { x = val; }
int valueX() { return x; }
};
int main() {
Location A;
A.valueX(); Error,编译起无法判断调用哪个valueX
return 0;
}