C++学习笔记_four_day

Oop编程示例:
1、经典案例:武林趣事
             
某年某月某日
            张无忌 偷袭了
令狐冲
            经 平一指 诊断 
令狐冲 受伤了
分析:
如何用程序实现上述事件?
(1)分析事件中有哪些名词和动词
(2)从类的角度将这些名次和动词联系在一起

案例设计:
(1)需要设计几个类?
(2)每个类的属性和行为是什么?
(3)如何使用这些类的对象?


//Fight.cc
#include <iostream>
using namespace std;

// 1.设计类
/**
* Hero 类
**/
class Hero
{
string m_name; // 姓名
bool m_status; // 身体状态
public:
Hero(string name):m_name(name)
{
m_status = true;
}
~Hero(){}

// 偷袭
void hurt(Hero &h)
{
cout << m_name << " 偷袭了 "
<< h.m_name << endl;

h.m_status = false;
return ;
}

// 诊断
void check(const Hero &h)
{
cout << " 经 " << m_name
<< " 诊断 " << h.m_name
<< (h.m_status?"无大碍":"受伤了") << endl;
return ;
}

};

int main(int argc,char **argv)
{
//2.创建对象
Hero h1("张无忌");
Hero h2("令狐冲");
Hero h3("平一指");

//3.使用对象(调用成员函数)
h1.hurt(h2);
h3.check(h2);

return 0;
}

  1. 实战演练:

  小明在老盛兴吃中饭
  小明向服务员点了一份糖醋排骨,
  服务员上了一份糖醋排骨,
  小明吃完中饭,向服务员支付了20元餐费,离开了老盛兴。


//Lunch.cc
#include <iostream>
using namespace std;
/**
* 服务员类
**/
class Waiter
{
string m_name; // 姓名
public:
Waiter(string name):m_name(name){}
~Waiter(){}

string GetName(){ return m_name;}
void server(int count,string name); // 上菜
};

// 上菜
void Waiter::server(int count,string food)
{
cout << m_name << " 上了 " << count << " 份 "<< food << endl;
return ;
}
/**
* 顾客类
**/
class Guest
{
string m_name; // 姓名
public:
Guest(string name):m_name(name){}
~Guest(){}

void order(Waiter &w); // 点菜
void pay(string name); // 付款
};

// 点菜
void Guest::order(Waiter &w)
{
int count; //菜的个数
string food; //菜的名称
cout << " ****点菜的过程*****" << endl;
cout << " 输入菜的份量:";
cin >> count;

cout << " 输入菜的名称:";
cin >> food;
cout << " *************** " << endl;
cout << endl;

cout << m_name << " 向 服务员 " << w.GetName()<< " 点了 " << count << " 份 "
<< food << endl;
cout << endl;
cout << "**过了若干分钟之后**" << endl;
cout << endl;

// 服务员上菜
w.server(count,food);

return ;
}

// 付款
void Guest::pay(string name)
{
double Money = 0;

cout << m_name
<< " 吃完了中饭" << endl;
cout << endl;

cout << " ****结帐的过程*****" << endl;
cout << "输入小明的付款金额:";
cin >> Money;
cout << " *************** " << endl;
cout << endl;

cout << m_name << "向 服务员 "<< name << " 支付了 "<< Money << " 元餐费,"
<< "离开了老盛兴" <<endl;

return ;
}

int main(int argc,char **argv)
{
//2.创建对象
Waiter w("小吴");
Guest g("陶嗣远");

//3.使用对象
g.order(w);
g.pay(w.GetName());

return 0;
}

  1. 实战演练:小甜甜在上嵌上课

马老师
在 项目一组 教 C++课程;

江老师
在 项目四组 教 ARM课程;

小甜甜
上午 在 项目一组 上 C++课程,

下午
在 项目四组 上 ARM课程。


 1 //Listen.cc
2 #include <iostream>
3 using namespace std;
4
5 //1.设计类
6 /**
7 * 教师类
8 **/
9 class Teacher
10 {
11 string m_name; // 姓名
12 string m_addr; // 上课地点
13 string m_course; // 课程名称
14 public:
15 Teacher(string name,string addr,string course):m_name(name),m_addr(addr),m_course(course){}
16 ~Teacher(){}
17
18 string GetAddr()
19 {
20 return m_addr;
21 }
22
23 string GetCourse()
24 {
25 return m_course;
26 }
27
28 // 授课
29 void teach();
30 };
31
32 // 授课
33 void Teacher::teach()
34 {
35 cout << m_name << " 在 "<< m_addr << " 教 "<< m_course << " 课程"<< endl;
36 return ;
37 }
38
39 /**
40 * 学生类
41 **/
42 class Student
43 {
44 string m_name;
45 public:
46 Student(string name):m_name(name){}
47 ~Student(){}
48
49 // 上课
50 void Listen(string szTime,Teacher &t);
51 };
52
53 // 上课
54 void Student::Listen(string szTime,Teacher &t)
55 {
56 cout << m_name << " " << szTime << " 在 " << t.GetAddr()<< " 上 " << t.GetCourse()
57 << endl;
58
59 return ;
60 }
61
62 int main(int argc,char **argv)
63 {
64 //2.创建对象
65 Teacher t1("马老师","项目一组","C++");
66 Teacher t2("江老师","项目四组","ARM");
67 Student s("小甜甜");
68
69 //3.使用对象
70 t1.teach();
71 t2.teach();
72
73 s.Listen("上午",t1);
74 s.Listen("下午",t2);
75 return 0;
76 }

4.实战演练:艾米在京东商城网购球鞋

艾米在京东商城订购了一双球鞋,

京东商城给艾米发了一双球鞋。

艾米对球鞋很满意,于是支付了货款;

艾米对球鞋很不满意,于是就退货了。


  1 //WebShop.cc
2 #include <iostream>
3 using namespace std;
4
5 /**
6 * 网店
7 **/
8 class WebShop
9 {
10 string m_name;
11 public:
12 WebShop(string name):m_name(name){}
13 ~WebShop(){}
14
15 string GetName(){ return m_name;}
16
17 // 发货
18 void send(string szGuest,int count,string brand,string goods);
19 };
20
21 // 发货
22 void WebShop::send(string szGuest,int count,string brand,string goods)
23 {
24 cout << m_name << " 给 "<< szGuest << " 发 "<< count << " 件 "
25 << brand << " " << goods<< endl;
26 return ;
27 }
28
29 /**
30 * 顾客类
31 **/
32 class Guest
33 {
34 string m_name;
35 public:
36 Guest(string name):m_name(name){}
37 ~Guest(){}
38
39 // 订购
40 void order(WebShop &w);
41 // 商品的处理
42 void deal(string goods);
43 };
44
45 // 订购
46 void Guest::order(WebShop &w)
47 {
48 int count;
49 string brand;
50 string goods;
51
52 cout << "**订货的过程**" << endl;
53 cout << "填写商品的个数:";
54 cin >> count;
55 cout << "填写商品的品牌:";
56 cin >> brand;
57 cout << "填写商品的种类:";
58 cin >> goods;
59 cout << "*************" << endl;
60 cout << endl;
61
62 cout << m_name << " 在 "<< w.GetName() << " 订购了 "<< count << " 件 "
63 << brand << " " << goods
64 << endl;
65
66 cout << "**经过3-5个工作日***" << endl;
67 cout << endl;
68
69 w.send(m_name,count,brand,goods);
70
71 deal(goods);
72
73 return ;
74 }
75
76
77 // 商品的处理
78 void Guest::deal(string goods)
79 {
80 bool result;
81
82 cout << "**检查商品的质量**"<<endl;
83 cout << "输入对商品的评价:";
84 cin >> result;
85 cout << "***************"<<endl;
86
87 cout << m_name << " 对 "<< goods << (result?"满意,支付货款":"不满意,退货") << endl;
88
89 return ;
90 }
91
92
93 int main(int argc,char **argv)
94 {
95 WebShop w("京东商城");
96 Guest g("吴尚奇");
97
98 g.order(w);
99 return 0;
100 }

Oop编程总结:

  1. 熟悉oop的编码流程

  2. Oop的核心:设计类

  3. 设计的注意点:

  1. 确定类与类之间是否存在交互

----决定了成员函数的形参是对象还是普通变量

  1. 确定事件的主动发生方和被动接收方

---决定了事件由主动发生方描述

思考题:面向过程和面向对象编程的区别

封装性上

面向对象的封装将一系列的数据和方法集中在类中

面向过程的封装,
方法一般不做封装, 数据用Struct封装, 方法和数据分离

代码复用性上

面向对象利用继承的方式复用

面向过程只能以普通的函数复用

其它的细节区别,
比如overload,
overwrite之类的区别, 属于语义上的区别, 不影响本文的主题.

面向对象之弊,面向过程之优

1. OO的特点,
就是把数据和逻辑封装成一个整体, 带来了强耦合的问题.

2. OP的特点,
数据和逻辑分开, 绝对的松耦合,
但封装性不够.

上述两个东东的互斥的特性, 给我们带来了非常重要的提示:

模块之间的设计,
为了维护代码(修改bug,
增加新功能, 独立协调成员工作).
严重关注耦合度, 要求尽量即插即用,
模块间完全独立. 这个时候我们需要尽量的按照OP的思路. 模块和模块之间的协作,
务必按照OP的思路.
逻辑分离得非常彻底.

内部单元的设计,
尽量封装良好, 利用OO的思想,
将各个零部件整理成一个类整体.

比如, 电脑的组装, 在整体上,
我们是通过电源线将机箱和插座, 以及显示器连接,
这个上面的设计思路, 是按照OP来的直观的连接流程(连接线可以视为胶合层,
《Unix编程艺术》上明确的要求这个层面尽量薄),
但机箱内部, 各个零件, 如DVD, 硬盘, 主板,
都是一个分装完美的对象, 包含数据,
也包含处理的动作. 这个可以实现插件的管理模式.

特别强调的一点, OP和OO的设计思路,
主要是看在哪个层次, "模块"和“内部单元”实质上是一个非常抽象的概念, 在某个层面上, “内部单元”可能是一个“模块”, 而在更大的层面上, "模块"也被当做一个“内部单元来处理”,
所以, 如何选择OO的设计方式, 还是OP的设计方式,
需要视情况而定. 我们所设计的任何一个点,
都停留在产品金字塔结构的一个“内部单元”中, 同时也停留在一个"模块中". 下图概括了上文的表述内容:

  1. Const

  常对象和常成员函数

  常成员函数:


 1
2 #include<iostream>
3 using namespace std;
4
5 class A
6 {
7 int m_data;
8 public:
9 A(int data):m_data(data){}
10 ~A(){}
11 //常成员函数,const在参数列表之后
12 //作用:限制成员数据的修改
13 void show() const
14 {
15 cout<<"show() const"<<endl;
16 // cout<<" m_data= "<<(++m_data)<<endl;//成员函数不能进行修改,将++去掉之后就不会报错了
17 return ;
18 }
19
20 //const也能构成函数的重载
21 void show()
22 {
23 cout<<"show() const"<<endl;
24 cout<<" m_data= "<<(++m_data)<<endl;
25 return ;
26 }
27 };
28
29 int main()
30 {
31 A a(10);
32 //普通函数 优先调用 普通的同名的成员函数
33 a.show();//调用方式和普通函数一样
34 return 0;
35 }

普通对象/常对象和普通成员函数/常成员函数的关系

普通对象
---优先调用--->普通成员函数

常对向
----只能调用 ---->常成员函数

作业:

设计一个字符串类String,要求如下:

1.实现4种构造函数

String
s1;

String
s2(s1);

String
s3("wushangqi");

String s4(4,‘a‘); //
用4个‘a‘初始化

2.实现empty(),size(),resize()函数;

3.只允许有一个成员char
*p;

参考资料:

C++中string类中函数的定义如下:

bool empty()const;
//当前字符串是否为空

int size()const; //
返回当前字符串大小

void resize(int
len,char c);//设置字符串当前大小置为len,并用字符c填充不足的部分


  1 //String.cc
2 #include <string.h>
3
4 #include <iostream>
5 using namespace std;
6
7 /*
8 1.实现4种构造函数
9 String s1;
10 String s2(s1);
11 String s3("shangqian");
12 String s4(4,‘a‘); // 用4个‘a‘初始化
13 2.实现empty(),size(),resize()函数;
14 3.只允许有一个成员char *p;
15 */
16
17 // 模仿 实现 系统提供的string类
18 class String
19 {
20 char *p;
21 public:
22 String();
23 String(const String &s);
24 String(const char *str);
25 String(int cnt,char ch);
26 ~String(){}
27
28 int size()const;
29 bool empty()const;
30 void resize(int len,char c);
31
32 void show();
33 };
34
35 // 1.实现无参的构造函数
36 String::String()
37 {
38 p = NULL;
39 }
40
41 // 2.实现拷贝构造函数
42 String::String(const String &s)
43 {
44 // 1.知道字符串的长度
45 int cnt = strlen(s.p);
46
47 // 2.p申请空间
48 p = new char[cnt+1];
49
50 // 3.拷贝值
51 strcpy(p,s.p);
52 }
53
54 // 3.带一个常字符串的构造函数
55 //String s3("shangqian");
56 String::String(const char *str)
57 {
58 // 1.知道字符串的长度
59 int cnt = strlen(str);
60
61 // 2.p申请空间
62 p = new char[cnt+1];
63
64 // 3.拷贝值
65 strcpy(p,str);
66 }
67
68 // 4.带两个参数的构造函数
69 String::String(int cnt,char ch)
70 {
71 // 1.p申请空间
72 p = new char[cnt+1];
73
74 // 2.拷贝值
75 int i;
76 for(i=0; i<cnt; ++i)
77 {
78 p[i]=ch;
79 }
80 }
81
82 // 5.判断字符串是否为空
83 bool String::empty()const
84 {
85 // NULL == 0 == ‘\0‘
86 return p;
87 }
88 // 6.返回字符串的长度
89 int String::size()const
90 {
91 return (empty()?strlen(p):0);
92 }
93
94 // X.显示字符串内容
95 void String::show()
96 {
97 cout << "字符串内容为:"
98 << p << endl;
99
100 return ;
101 }
102
103 int main(int argc,char **argv)
104 {
105 String s1;
106
107 // 0?"是":"不是"
108 // 位置需要根据实际情况调整 陷阱
109 cout << " String s是否为空:"<< (s1.empty()?"不是":"是")<< endl;
110
111 cout << " String s的长度:"<< s1.size() << endl;
112
113 cout << "*****String s2(\"wushangqi\");*****"<< endl;//注意转义字符‘\’
114
115 String s2("shangqian");
116 s2.show();
117
118 //注意:陷阱等效与0?“不是”:“是”
119 cout << " String s是否为空:"<< (s2.empty()?"不是":"是")<< endl;
120
121 cout << " String s的长度:"
122 << s2.size() << endl;
123
124 cout << "*****String s3(5,‘c‘);*****"<< endl;
125
126 String s3(5,‘c‘);
127 s3.show();
128
129 cout << " String s是否为空:"<< (s3.empty()?"不是":"是") << endl;
130
131 cout << " String s的长度:" << s3.size() << endl;
132
133 cout << "*****String s4(s2);*****"<< endl;
134
135 String s4(s2);
136 s4.show();
137
138 cout << " String s是否为空:"<< (s4.empty()?"不是":"是")<< endl;
139
140 cout << " String s的长度:"<< s4.size() << endl;
141
142 return 0;
143 }

补:拷贝构造函数

拷贝构造函数,经常被称作X(X&),是一种特殊的构造函数,他由编译器调用来完成一些基于同一类的其他对象的构件及初始化。它的唯一的一个参数(对象的引用)是不可变的(因为是const型的)。这个函数经常用在函数调用期间于用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。

在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。

1). 一个对象以值传递的方式传入函数体

2). 一个对象以值传递的方式从函数返回

3). 一个对象需要通过另外一个对象进行初始化

以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作赋共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。

拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环。

除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。换句话说,你从函数返回得到的只是对象的一份拷贝。但是同样的,拷贝构造函数被正确的调用了,你不必担心。

如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会私下里为你制定一个函数来进行对象之间的位拷贝(bitwise
copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。许多作者都会提及这个默认的拷贝构造函数。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对于成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数除非另外一个构造函数在类初始化或者在构造列表的时候被调用。

拷贝构造函数是程序更加有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统提供的帮助你申请内存默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。

C++学习笔记_four_day

时间: 2024-08-03 15:18:43

C++学习笔记_four_day的相关文章

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu

jQuery学习笔记(一):入门

jQuery学习笔记(一):入门 一.JQuery是什么 JQuery是什么?始终是萦绕在我心中的一个问题: 借鉴网上同学们的总结,可以从以下几个方面观察. 不使用JQuery时获取DOM文本的操作如下: 1 document.getElementById('info').value = 'Hello World!'; 使用JQuery时获取DOM文本操作如下: 1 $('#info').val('Hello World!'); 嗯,可以看出,使用JQuery的优势之一是可以使代码更加简练,使开

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

Activiti 学习笔记记录(三)

上一篇:Activiti 学习笔记记录(二) 导读:上一篇学习了bpmn 画图的常用图形标记.那如何用它们组成一个可用文件呢? 我们知道 bpmn 其实是一个xml 文件

HTML&CSS基础学习笔记8-预格式文本

<pre>标签的主要作用是预格式化文本.被包围在 pre 标签中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre>标签的一个常见应用就是用来表示计算机的源代码.当然你也可以在你需要在网页中预显示格式时使用它. 会使你的文本换行的标签(例如<h>.<p>)绝不能包含在 <pre> 所定义的块里.尽管有些浏览器会把段落结束标签解释为简单地换行,但是这种行为在所有浏览器上并不都是一样的. 更多学习内容,就在码芽网http://www.

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

[原创]java WEB学习笔记48:其他的Servlet 监听器:域对象中属性的变更的事件监听器 (3 个),感知 Session 绑定的事件监听器(2个)

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过