Essential C++学习记录&笔记整理21(如何实现一个class)

这章第一节就,,,,比较生涩,慢慢接受吧。。。
给代码解释一些东西,或许更清晰明了!

如何实现一个class

其实懂个框架就好,不要一口吃个胖子。
一切都在注释里!

练习4-1

//stack.h文件
#ifndef _STACK_H_
#define _STACK_H_//头文件定义格式
#include<string>
//E:\STUDY\ConquerCPP\exercise41\stack.h|3|fatal error: string: No such file or directory|
//关于这个错误,是因为我头文件附属的程序代码文件是c而非cpp!!!
#include<vector>
using namespace std;//这个不要忘了!
class Stack{//定义栈这个类的格式
public://类的公共接口,用户可以用其包含在内的函数,而且公共成员可以在程序的任何地方被访问
    bool push(const string&);//入栈函数声明
    bool pop(string &elem);//出栈函数声明
    bool peek(string &elem);//取栈顶元素函数声明
    bool empty()const;//判断栈空函数声明,定义在程序代码文件(stack.cpp)
    bool full()const;//判断栈满函数声明,定义在程序代码文件
    //这些成员函数的定义都定义在了类(class)主体之外了。放在了stack.c文件里。
    int size()const//这里加const可以提高程序可读性和可靠性,上同。意思是表示函数不可以修改class的成员,注意该函数声明也要加上const!!!!
    {
        return _stack.size();//定义求栈元素多少的函数。
    }
private://类的实现部分,用户只能在成员函数或者是类友元内被访问。
    vector<string> _stack;//一个string型的vector容器
};


#endif//至此所有成员函数和成员变量我都(有的声明完了)定义完了

用到了分文件编程的形式,关于如何分文件编程,参考我的单片机IIC总线的博客。单片机IIC总线和EEPROM的学习(包括建立头文件及头文件附属的.c文件并将其囊入项目(组)的过程)

  • 一般是这种格式。把类定义在头文件里。
#include"stack.h"//头文件所附属的代码文件里存放在类主体外定义的成员函数!!!所以这个头文件必须包含
#include<string>
#include<vector>
#include<iostream>
using namespace std;
//注意,这些类成员函数的类主题外定义我放在了程序代码文件,这是规定。
void fill_stack(Stack &stack,istream &is=cin)//在头文件里定义并使用stack类对象,整个为定义stack类对象。同时提供默认参数(默认从键盘里输入)
{//用到了cin,就要包含iostream头文件
    string str;
    while(is>>str&&!stack.full())
    {
        //栈未满,则往里充字符串。
        stack.push(str);//使用stack类对象。
    }
    cout<<"Read in "<<stack.size()<<" elements\n";//使用stack类对象
}//所有成员函数(上面那个fill_stack不是,而class public:里头的一堆函数是成员函数)
//必须在class主体内进行声明,是否同时定义,看自己(上面那个fill_stack就同时定义了)
//如果在类主体里定义成员函数,该成员函数自动被视为内联(inline)函数,例如上面的类主体内的size()函数(stack的一个内联成员)
inline bool//表明在类主体外定义的成员函数是内联函数
Stack::empty() const//这里加const可以提高程序可读性和可靠性,意思是表示函数不可以修改class的成员,注意该函数声明也要加上const!!!!
//如果在类主体外定义成员函数,必须标明该成员函数属于哪一个类,如下一行Stack::
{//实际上你把inline bool和Stack::empty()放在一行也行,下同。
    return _stack.empty();
}
bool//这个在类主体外定义的成员函数就不是内联函数了,定义规则还是和上面那个内联函数的定义规则一致。
Stack::pop(string &elem)//弹出(删除)栈顶元素。
{
    if(empty())//栈空了额就不用删除了
    {
        return false;
    }
    elem=_stack.back();
    _stack.pop_back();//删除栈顶元素的具体操作
    return true;
}
inline bool//定义规则参照第一个定义在类Class主体外的内联成员函数
Stack::full()const//这里加const可以提高程序可读性和可靠性,意思是表示函数不可以修改class的成员,注意该函数声明也要加上const!!!!
//这个函数很短小,所以就用内联函数即可(不要忘了内联函数的目的!)
{
    return _stack.size()==_stack.max_size();
}
bool Stack::peek(string &elem)//返回栈顶元素(这里我就把Stack::peek和bool这个函数返回类型放在了一起。)
{
    if(empty())//栈空了就不用取栈顶元素了
    {
        return false;
    }
    elem=_stack.back();
    return true;
}
bool Stack::push(const string &elem)//这里用了const是代表elem我没修改,而上面没加const是因为我要修改elem
{
    if(full())//栈满了就不用添加了
    {
        return false;
    }
    _stack.push_back(elem);//栈没满,往栈顶放东西
    return true;
}

stack.h附属的程序代码文件(.cpp)。

#include<iostream>
#include<string>
#include<vector>
#include"stack.h"//用到stack class头文件里的函数了,必须包含该头文件
using namespace std;
int main()
{
    Stack st;//使用了Stack这个类,主函数运用Stack类的公共接口
    string str;
    while(cin>>str&&!st.full())//注意我定义了个Stack这个类的对象st,然后我用了Stack类的公共接口(使用并操作于类对象st上)
    {//注意,需要ctrl+z来结束输入。
        st.push(str);
    }//我从标准输入设备(比如键盘)上读取字符串,如果类对象st这个栈(vector<string>型)没有满,就往里压入字符串
    if(st.empty())
    {
        cout<<'\n'<<"No strings were read--bailing out\n";//如果类对象st这个栈是空的,则输出。。。。
        return 0;//栈空就不用执行下面的操作了
    }
    st.peek(str);//取栈顶元素元素赋给str,以备下面的str.empty()使用
    if(st.size()==1&&str.empty())
    {
        //if条件里的表达式很巧妙,&&优先级小于==,!!!!!!注意,是&&优先级小于==!!!!!
        //那么先判断栈st这个类对象有没有元素,如果有元素,并且只有一个元素,那么==这里就是true,相当于1&&str.empty(),
        //然后判断取出的栈顶元素(字符串)是不是空串,是空串的话.emtpy()会返回true,则整个条件语句为true,走if里。
        //否则,如果st这个栈里有两个元素及以上的话或者栈没有元素或者取出的栈顶元素不是空的话,都不会走if,有点绕,慢慢理解
        //总的来说,就是栈里只有一个元素,st.size()返回1,但是取栈顶元素可能操作失败了,然后导致没取到栈顶元素给str,导致str.empty()返回true,
        //然后满足了条件,然后走if里。
        cout<<'\n'<<"No strings were read--bailing out\n";
        return 0;
    }
    cout<<'\n'<<"Read in"<<st.size()<<"strings!\n";//没走if的话,证明栈里有0个或两个及以上字符串元素了
    cout<<"The strings,in reverse order:\n";//字符串,反转命令?
    while(st.size())//栈里有元素的话
    {
        if(st.pop(str))//如果栈里能弹出元素给str
        {
            cout<<str<<' ';//输出弹出的元素
        }
    }
    cout<<'\n'<<"There are now "<<st.size()
        <<" elemnts in the stack!\n";//弹出元素后表示一下现在st这个栈里有多少元素了。
}

主函数程序代码文件
程序运行结果:
在这里插入图片描述
读取了10个字符串,然后反转这些字符串排序(纯纯粹粹的反转)

练习4-2

#ifndef _STACK_H_
#define _STACK_H_//头文件定义格式
#include<string>
//E:\STUDY\ConquerCPP\exercise41\stack.h|3|fatal error: string: No such file or directory|
//关于这个错误,是因为我头文件附属的程序代码文件是c而非cpp!!!
#include<vector>
using namespace std;//这个不要忘了!
class Stack{//定义栈这个类的格式
public://类的公共接口,用户可以用其包含在内的函数,而且公共成员可以在程序的任何地方被访问
    bool push(const string&);//入栈函数声明
    bool pop(string &elem);//出栈函数声明
    bool peek(string &elem);//取栈顶元素函数声明
    bool empty();//判断栈空函数声明,定义在程序代码文件(stack.cpp)
    bool full();//判断栈满函数声明,定义在程序代码文件
    //这些成员函数的定义都定义在了类(class)主体之外了。放在了stack.c文件里。
    int size()
    {
        return _stack.size();//定义求栈元素多少的函数。
    }
    bool find(const string &elem)const;
    int count(const string &elem)const;//声明别忘了,这是在练习4-1的基础上添加了两个函数声明,其附属的cpp文件添加了这两个函数的定义(利用了泛型算法
    //里的泛型指针)
private://类的实现部分,用户只能在成员函数或者是类友元内被访问。
    vector<string> _stack;//一个string型的vector容器
};


#endif//至此所有成员函数和成员变量我都(有的声明完了)定义完了

头文件(stack.h)

#include"stack.h"//头文件所附属的代码文件里存放在类主体外定义的成员函数!!!所以这个头文件必须包含
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>//下面会用到
using namespace std;
//注意,这些类成员函数的类主题外定义我放在了程序代码文件,这是规定。
void fill_stack(Stack &stack,istream &is=cin)//在头文件里定义并使用stack类对象,整个为定义stack类对象。同时提供默认参数(默认从键盘里输入)
{//用到了cin,就要包含iostream头文件
    string str;
    while(is>>str&&!stack.full())
    {
        //栈未满,则往里充字符串。
        stack.push(str);//使用stack类对象。
    }
    cout<<"Read in "<<stack.size()<<" elements\n";//使用stack类对象
}//所有成员函数(上面那个fill_stack不是,而class public:里头的一堆函数是成员函数)
//必须在class主体内进行声明,是否同时定义,看自己(上面那个fill_stack就同时定义了)
//如果在类主体里定义成员函数,该成员函数自动被视为内联(inline)函数,例如上面的类主体内的size()函数(stack的一个内联成员)
inline bool//表明在类主体外定义的成员函数是内联函数
Stack::empty()//如果在类主体外定义成员函数,必须标明该成员函数属于哪一个类,如下一行Stack::
{//实际上你把inline bool和Stack::empty()放在一行也行,下同。
    return _stack.empty();
}
bool//这个在类主体外定义的成员函数就不是内联函数了,定义规则还是和上面那个内联函数的定义规则一致。
Stack::pop(string &elem)//弹出(删除)栈顶元素。
{
    if(empty())//栈空了额就不用删除了
    {
        return false;
    }
    elem=_stack.back();
    _stack.pop_back();//删除栈顶元素的具体操作
    return true;
}
inline bool//定义规则参照第一个定义在类Class主体外的内联成员函数
Stack::full()//这个函数很短小,所以就用内联函数即可(不要忘了内联函数的目的!)
{
    return _stack.size()==_stack.max_size();
}
bool Stack::peek(string &elem)//返回栈顶元素(这里我就把Stack::peek和bool这个函数返回类型放在了一起。)
{
    if(empty())//栈空了就不用取栈顶元素了
    {
        return false;
    }
    elem=_stack.back();
    return true;
}
bool Stack::push(const string &elem)//这里用了const是代表elem我没修改,而上面没加const是因为我要修改elem
{
    if(full())//栈满了就不用添加了
    {
        return false;
    }
    _stack.push_back(elem);//栈没满,往栈顶放东西
    return true;
}
bool Stack::find(const string &elem)const{//这里加const可以提高程序可读性和可靠性,意思是表示函数不可以修改class的成员,
//注意该函数声明也要加上const!!!!
    vector<string>::const_iterator end_it=_stack.end(),it=_stack.begin();//注意用了泛型指针(常量泛型指针),因为该函数也不需要修改什么对象和class的成员
    return ::find(it,end_it,elem)!=end_it;//很巧妙的一种写法,找到了肯定find()不能返回end_it这个泛型指针,所以即Stack::find返回了true,如果find
    //返回了end_it,证明没找到,即Stack::find返回了false
}
int Stack::count(const string &elem)const
{
    return ::count(_stack.begin(),_stack.end(),elem);
}

程序代码文件。

//读取了10个字符串,然后反转这些字符串排序(纯纯粹粹的反转)
#include<iostream>
#include<string>
#include<vector>
#include"stack.h"//用到stack class头文件里的函数了,必须包含该头文件
using namespace std;
int main()
{
    Stack st;//使用了Stack这个类,主函数运用Stack类的公共接口
    string str;
    while(cin>>str&&!st.full())//注意我定义了个Stack这个类的对象st,然后我用了Stack类的公共接口(使用并操作于类对象st上)
    {//注意,需要ctrl+z来结束输入。
        st.push(str);
    }//我从标准输入设备(比如键盘)上读取字符串,如果类对象st这个栈(vector<string>型)没有满,就往里压入字符串
    if(st.empty())
    {
        cout<<'\n'<<"No strings were read--bailing out\n";//如果类对象st这个栈是空的,则输出。。。。
        return 0;//栈空就不用执行下面的操作了
    }
    st.peek(str);//取栈顶元素元素赋给str,以备下面的str.empty()使用
    if(st.size()==1&&str.empty())
    {
        //if条件里的表达式很巧妙,&&优先级小于==,!!!!!!注意,是&&优先级小于==!!!!!
        //那么先判断栈st这个类对象有没有元素,如果有元素,并且只有一个元素,那么==这里就是true,相当于1&&str.empty(),
        //然后判断取出的栈顶元素(字符串)是不是空串,是空串的话.emtpy()会返回true,则整个条件语句为true,走if里。
        //否则,如果st这个栈里有两个元素及以上的话或者栈没有元素或者取出的栈顶元素不是空的话,都不会走if,有点绕,慢慢理解
        //总的来说,就是栈里只有一个元素,st.size()返回1,但是取栈顶元素可能操作失败了,然后导致没取到栈顶元素给str,导致str.empty()返回true,
        //然后满足了条件,然后走if里。
        cout<<'\n'<<"No strings were read--bailing out\n";
        return 0;
    }
    cout<<'\n'<<"Read in "<<st.size()<<" strings!\n";//没走if的话,证明栈里有0个或两个及以上字符串元素了
    cin.clear();//清除EOF的设定。
    cout<<"what word to search for?";//你想查栈里哪个元素?
    cin>>str;
    bool found=st.find(str);//查找栈里某个元素(字符串)然后返回泛型指针给found
    int count=found?st.count(str):0;//条件表达式,如果found为true(因为found是bool变量)
    //详情请看成员函数find()。证明从st这个Stack类对象(栈)查找到了想要查找的元素,然后统计一下st里
    //有多少个想要查找到的字符串。若found=false,证明st这个栈里没有元素。count=0即可
    cout<<str<<(found?" is ":" isn't ")<<"in the stack.";//好,根据found是true还是false,found是true则输出查找的元素在st这个Stack类对象里。
    //否则输出查找的元素不在st这个类对象里。
    if(found)
    {
        cout<<"It occurs "<<count<<" times\n";//在St里找到了多少个要查找的元素。
    }
    return 0;
    /*以下为练习4-1的专属部分。练习4-2在此有另一种写法。
    cout<<"The strings,in reverse order:\n";//字符串,反转命令?
    while(st.size())//栈里有元素的话
    {
        if(st.pop(str))//如果栈里能弹出元素给str
        {
            cout<<str<<' ';//输出弹出的元素
        }
    }
    cout<<'\n'<<"There are now "<<st.size()
        <<" elemnts in the stack!\n";//弹出元素后表示一下现在st这个栈里有多少元素了。
    */
}

主函数文件
程序运行结果:
在这里插入图片描述
只能查询一次。。。。可以设置循环来查询多次。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值