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