第十章 对象和类
2020-02-24 10:42:05 11 举报
AI智能生成
C++ plus
作者其他创作
大纲/内容
OOP特性
抽象
封装和数据隐藏
多态
继承
代码的可重用性
过程性编程和<br>面向对象编程
区别
过程性编程
解决问题步骤
1.考虑遵循的步骤
2.考虑如何表达这些数据
面向对象编程
步骤
1.考虑如何表达数据
2.考虑如何使用数据
用户与数据<br>交互的方式<br>(3种)
初始化
更新
报告
说明
这是用户接口
oop方法
1.从用户的角度考虑对象
对象需要的数据、用户与数据的操作
2.确定如何实现接口和数据存储
3.使用新的设计方案创建出程序
抽象和类
类型是什么
内置类型
C/C++指定基本类型<br>完成三项工作
决定数据对象需要的内存数量
决定如何解释内存中的位<br>(long 和float 在内存中占用的位数相同,<br>但将他们转换为数值的方法不同)
决定可使用数据对象执行的操作或方法
用户自定义类型
C++允许
C++中的类
类作用
将抽象转换为用户定义类型的C++工具
将数据表示和操作数据的方法组合成一个简洁的包
类组成
类声明
以数据成员方式描述数据部分
以成员函数(称为方法)的方式描述公有接口
接口
类的接口指的是公共接口,<br>由编写类的人提供的方法组成。
eg:方法size()是用户和string类对象<br>之间的公共接口组成部分。
类方法定义
描述如何实现类成员函数
创建类<br>(类声明)
格式
<div>class Stock</div><div>{</div><div>private:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>std::string company;//存储公司</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>long shares;//存储持有的股数</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>double share_val;//每股的价格</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>double total_val;//全部股票的价格</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>void set_tot(){ total_val = share *share_val}//内联函数</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>void acquire(const std::string &co,long n, double pr);// 第一次购买</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>void buy(long num,double price);//在有的基础上买</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>void update( double price );//卖出</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>void show();//显示上面的数据</div><div><span class="Apple-tab-span" style="white-space:pre"> </span></div><div>};</div>
说明
一般在头文件中定义,main 外部,不要忘了 ;
一般约定——类名首字母大写
public 中的函数就是Stock 的成员函数
创建类对象
Stock sally;<br>Stock solly;
访问控制
含义
private、public 描述了对类的访问控制
使用类对象的程序,可以直接访问公有部分,只能通过<br>公有程序函数访问对象的私有成员
只能通过调用acquire()访问 shares之类的
封装
含义
将实现细节放在一起并将它们与抽象分开被称为封装
例子
数据隐藏(将数据放在类的私有部分),实现的细节隐藏到私有部分
将类函数定义和类声明放在不同的文件中
隐藏数据的好处
放置直接访问数据
不需要了解数据如何被表示
不需要修改程序接口,程序维护更容易
只需要知道类的成员函数的功能,返回值即可
控制对成员的访问:<br>公有还是私有
数据项通常放在私有部分,<br>组成类接口的成员函数放在公有部分
成员函数可以放在私有部分,来处理不属于公有接口的实现细节,<br>但程序不可以调用这个函数
private,可以省略,因为这是类对象的默认访问控制
实现类成员函数<br>(类方法定义)
成员函数特征
定义成员函数时,使用作用域解析运算符(::)<br>表示函数所属的类
类方法可以访问类的private组件
函数定义格式
void Stock::updata( double price)<br>{<br> share_value = price;//可以直接用 private的组件。<br> set_tot();<br>}
详细代码在p345
说明
位置在int main外
set_tot( )定义位于类声明中,自动成为内联函数
也可以在类声明外定义内联函数。定义 + inline<br>
inline void Stock::set_tot()<br>{<br> ....\<br>}
const 成员函数<br>使对象数据不可修改
情况
const Stock land = Stock( " Kludgehorn Properties " );<br>land.show()//invalid
原因
show没有参数,无法将函数参数声明为const ,不能确保调用对象不被修改
方法
原型
void show() const;
定义
void Stock::show() const<br>{<br> ....<br>}
作用
称为const 成员函数,保证了成员函数不会<br>修改调用对象(即成员函数自身对象的成员数据)
函数不会修改调用对象
对象数据不被修改
两回事吧
方法使用哪个对象
对象创建
Stock kate,joe;
使用对象成员函数
kate.show()
对象存储空间
每个对象<b>都有自己的存储空间</b>,存储其<b>内部变量和类成员</b>。
<b>但同一个类的所有对象共享同一组类方法</b>
p349图
使用类
创建类对象
创建变量
创建new动态
Stock *sally = new Stock;
类对象操作
初始化
构造函数初始化。(下)
对象赋值
Stock stock1,stock2;<br>stock1=stock2;
赋的是数据成员
Stock stock1;<br>stock1 = Stock("XXX company", 200 , 5.2 )
使用类函数
sally.show()
作为函数的参数和返回值
下有
类对象指针操作
创建
子主题
初始化
Stock *pstock = new Stock(' xxx company' , 500 , 2.5)
使用类函数
pstock->show( );
(*pstock).show( )
其它
ios_base在名称空间std中
类的构造函数<br>和析构函数
构造函数
前言
类对象,如Stock类的对象不能被初始化
Stock hot = {"Sukie's Autos ,Inc" , 200 , 50.25 };//invalid
类构造函数的作用
构造新对象、将值赋给它们的数据成员。
类构造函数特点
原型和函数头没有声明类型
没有返回值,没有被声明为void类型
函数类型即它的返回类型
声明和定义<br>构造函数
原型
Stock( const string & co , long n , double pr)
说明
位于类声明的公有部分
一般把构造函数的构造名称称为 Stock
定义
Stock::Stock(const string & co , long n , double pr)<br>{<br> company = co;<br> if ( n < 0 )<br> {<br> std::cerr<<"Number od shares can`t be negative; "<br> <<company<<" shares set to 0.\n";<br> share = 0;<br> }<br> else<br> share = n;<br> share_val = pr;<br> set_tot( );<br>}
说明
程序声明对象时候,将自动调用构造函数
类数据成员名和参数名不能相同。
Stock::Stock(const string & company , long shares , double share_val)<br>{<br>.....<br>}//是不可以——最后代码会变成 shares = shares;//因为shares数据成员<br>可以在任一同类函数中使用,这样会造成混乱
解决上方法
在数据成员中使用m_前缀
是数据成员
数据成员使用后缀 _
使用构造函数
初始化对象方式
方式
一般方式
显式调用构造函数
Stock food = Stock( ''World Cabbage" , 250 , 1.25 ) ; #1
隐式调用够澡函数
Stock food ( ''World Cabbage" , 250 , 1.25 ) ; #2
new
Stock *pstock = new Stock( "Electroshock Games", 18 , 19.0 );
C++11
Stock Sally = { "World Cabbage"", 250 ,1.25 }
Stock Sally { .... }
Stock *pSally = new Stock{ .... }
构造函数只有<br>一个参数时候
Bozo dribble = Boze(44);<br>
Bozo roon(60);
<b>Bozo tubby = 32; //</b>
属于新内容,<br>它可能带来令人不愉快的意外
说明
每次创建类对象(包括使用new动态分配内存时候),<br>C++都使用类构造函数。//都使用??,没有初始化会发生什么??
不能用对象调用构造函数,stock1.Stock( );//不可以。
因为在构造函数造成对象之前,对象是不存在的。//???
原理
#2 表示 :创建一个food对象,并初始化。<br>#1 可以表示:创建一个food对象,并初始化。<br> 或者:创建一个临时对象调用构造函数,然后将临时对象复制到stock2中,并丢弃它。一般前者
给对象赋值
格式
Stock stock2;<br>.......<br>stock2=Stock( ..... )
原理
创建一个临时对象调用构造函数,然后将临时对象复制到stock2中,并丢弃它。
说明
初始化的方式效率更高
默认构造函数
类型
实现提供
情况
声明 Stock Sally;<br>用户没有提供任何构造函数,C++将自动提供默认构造函数。
C++将自动提供的默认构造函数是<br>默认构造函数的隐式版本。
可能定义形式
Stock::Stock() { }
说明
不会给成员数据赋任何值,即没有初始化。
要求
用户没有提供构造函数。才调用
若用户提供了构造函数,且创建对象时候。<br>Stock Sally;//会报错
用户自定义
给已有的构造函数<br>所以参数提供默认值
Stock( const string & co = “ Error ” , long n =0 , double pr = 0.0 )<br>//注意只能是从右往左
函数重载定义<br>另一个构造函数
原型
加上;<br>Stock();
定义
Stock::Stock()<br>{<br> company = " no name ";<br> shares = 0;<br> share_val = 0.0;<br> total_val = 0.0;<br>}
说明
Stock Sally ; 就不会报错了,而且还被初始化了。<br><b>Stock Sally();</b>这样是错误的注意,这样表示Sally 是一个返回Stock<br>对象的函数。
析构函数<br>(p355)
作用
用构造函数创建对象后,对象过期时,程序自动调<br>用析构函数,完成清理工作。
如果构造函数使用new来分配内存——析构函数将使用delete来释放内存。
构造函数没有使用new就实际上没有需要完成的任务??<br>这时候编译器会生成一个什么不要做的隐式析构函数。
名称
~Stock(前缀~)
原型
~Stock();
说明
没有类型,(返回值)
定义
Stock::~Stock()<br>{<br>}
看出什么时候被调用:<br>Stock::~Stock()<br>{<br> cout<<"Bye"<<endl;<br>}
调用析构函数<br>的时候
创建静态存储类对象
程序结束时候自动被调用
创建自动存储类对象
执行完代码块自动被调用
new创建对象
使用delete 来释放内存时候
临时对象。
对象被删除的时候
说明
程序员没有提供析构函数,<br>编译器隐式地声明一个默认析构函数。
代码p356<br>好好研究
使对象数据不可修改
情况
const Stock land = Stock( " Kludgehorn Properties " );<br>land.show()//invalid
原因
show没有参数,无法将函数参数声明为const ,不能确保调用对象不被修改
方法
原型
void show() const;
定义
void Stock::show() const<br>{<br> ....<br>}
作用
称为const 成员函数,保证了成员函数不会<br>修改调用对象(即成员函数自身对象的成员数据)
函数不会修改调用对象
对象数据不被修改
两回事吧
This指针
问题
方法(成员函数)涉及两个对象,如何处理?
作用
this 指针指向用来调用该方法的对象。
即Stock stock1,stock2;<br>stock1.topval( stock2 );--->this 指针指向stock1 对象的地址。<br>使这个指针可用于topval()方法<br>
特点
每个成员函数(包括构造、析构)<br>都有一个this 指针 指向调用它的对象的地址。
void Stock::show() const<br>{<br> .......<br>}<br>实际上是:<br>void show( const Stock * this)
在成员函数中使用 shares_value 实际上是 this->shares_value .
成员函数括号后有const ,将this 限定为const ,<br>不能使用this 修改对象(即不能修改对象成员)
格式
这里成员函数作用
比较两个Stock 对象,并返回股价较高的那个对象的引用
原型
const Stock & topval( const Stock & s ) const;
说明
括号const表示
不会修改被显式地访问的对象
显式访问
Stock stock1,stock2;<br>stock1.topval( stock2 );
stock1 —— 隐式访问<br>stock2——显式访问
括号后const表示
函数不会修改被隐式地访问的对象。
隐式访问
括号前 const
返回不可修改的对象引用(对象本身)
一般指不可当左值
定义
const Stock & Stock::topval( const Stock & s ) const<br>{<br> if ( s.total_val > total_val );<br> return s;<br> else<br> <b> return *this;</b><br>}
说明
*this 表明返回的是对象本身。
main()中使用
简单使用
//比较两个对象<br>Stock top;<br>top = stock1.topval( stock2 );<br><br>
//比较多个<br>Stock *top = &stock[0];<br>for( st = 1 ; st<STKS; st++)<br> top = &top->toval( stocks[ st ] )
对象数组
创建
Stock stocks[4];
说明
这样会调用默认构造函数。
初始化
Stock stocks[4] = {<br><b>Stock( "NanoSmart" , 12.5 , 20 ),//<br>Stock( );//调用默认<br>Stock( "" , 130 , 3.25)</b><br> //剩余调用默认<br>};
原理
首先使用默认构造函数创建数组元素,如果有初始化,<br>然后花括号中的构造函数将创建临时对象,然后将临<br>时对象内容复制到相应的元素中。
必须有默认构造函数
类作用域
含义
在类中定义的名称(成员数据名和成员函数名)的作用域为整个类。
不同类的类成员名可以相同
不能从外部直接访问类的成员,公有成员函数要 sleeper.show( ),即<br>要有对象。
公有函数定义要加 ::
作用域为类的<br>常量
方式
class Bakery<br>{<br>private:<br> <b>const int Months = 12;</b><br> double costs[ Months ];<br> .....<br><br>
不可以
声明类只是描述了对象的形式,没有创建对象。
方式1
private:<br> <b>enum{ Months = 12 };</b><br> double costs[ Months ];<br>
说明
不会创建类数据成员,所有对象中都不包含枚举
Months只是一个符号名称,编译器会用12代替它
不需要提供枚举名
方式2
private:<br> <b>static const int Months = 12;</b><br> .....
说明
变量与其它静态变量存储在一起,不是存储在对象中。
但是使用它也需要指定类(在类外的时候)的作用域<br>
作用域内枚举(C++11)
传统枚举:两个枚举定义中的枚举量可能会发生冲突
enum egg {Small , Medium , Large , Jumbo };<br>enum t_shirt { Small , Medium , Large ,Xlarge };//
声明
enum class egg {Small , Medium , Large , Jumbo };<br>enum class t_shirt { Small , Medium , Large ,Xlarge };
说明
也可以用struct 替代class
使用
egg choice = egg::Large;
t_shirt Flory = t_shirt::Large;
特点
作用域内不能隐式地转换为整形
t_shirt rolf = t_shirt::Large;<br>int king = rolf ;//invalid;
如果一定要转换为整形
int king = ( int )rolf
那就是0 , 1 ,2,3...是有的。
其他
枚举用哪种底层类型可以设置
语法
enum <b>class : short</b> pizza { Small , Medium , Large , XLarge };
抽象数据类型
p373代码栈的创建??
0 条评论
下一页