首页 > 编程语言 >定义模板,同时将类定义与类实现分离(C++,以栈为例)

定义模板,同时将类定义与类实现分离(C++,以栈为例)

时间:2024-10-13 15:47:35浏览次数:10  
标签:定义 temp 为例 pTop 将类 SNode next pStack Stack

一 问题背景:

        在以往单独实现树或栈时,只需要在开始使用typedef定义ElemType,后文便不必再考虑数据类型.

        但是,在实现二叉树非递归遍历时,需要借助额外的栈,树内数据类型为ElemType,但是栈内的数据类型为树节点,或者说指向树的指针,c++自带<stack>库,可以通过下列代码实现:

#include<iostream>
#include<stack>
using namespace std;
typedef int ElemType;
typedef struct TNode{
    ElemType data;
    TNode *lchild,*rchild;
}TNode,*BiTree;//定义树节点

void NLEnoRecursion(BiTree T){
    stack<BiTree> S;//使用stack库生成栈

        我们可以看到,<stack>库在生成栈时就用到了模板的知识.在定义Class类时,可以先不指定元素的数据类型,或者说可以用T来代替数据类型:

template <typename T>
typedef struct SNode{
        T data;
        struct SNode* next;
    }SNode,*pStack;

        使用<stack>库很方便快捷,并且已经足够解决遍历树的问题.但是为了更深入地学习,下面我们尝试自己编写stack模板.但是在单个文件内同时实现树与栈各种定义会很杂,而且很不好维护,所以我们考虑编写Stack类,并将类定义与实现分离.

二 Stack类的编写(不使用模板)

        为防止混淆,我们先不管模板,先把类定义搞清楚.

        class可以将类定义与类实现分离.需要注意的是,我们先将元素类型T用int来表示,待调试无误之后再扩展为模板,以下为代码,需要注意的地方都写在注释里:

#include<iostream>
using namespace std;

//template <typename T>
typedef int T;
typedef struct SNode{
        T data;
        struct SNode* next;
    }SNode,*pStack;


class Stack{
public:
    pStack pTop= new SNode;;//SNnode是我们自己创建的新数据类型,与int,float地位一致
    Stack();
    /*使用Stack()为无参构造函数,用于初始化数据域
    构造函数名字必须与类名相同,构造函数前面不需要void等返回类型
    下方Stack(pStack)同样为构造函数,用pStack将Stack初始化,即当输入一个栈时,S即指向该栈.
    */
    Stack(pStack);
    bool empty();
    bool push(T);
    bool pop();
    int length();
    T top();
};

//类可以将定义与实现分离,以上class定义类,以下代码实现class的各种操作
Stack::Stack(){
    pTop->next = NULL;
}
Stack::Stack(pStack NewStack){
    pTop = NewStack;
}
//这里用带头节点的链表来定义栈,故第一个元素为S->next,为NULL则栈空,pop失败
bool Stack::empty(){
    if (pTop->next == NULL)return true;
    else return false;
}
bool Stack::push(T n){
    SNode* temp = new SNode;
    temp->data = n;
    temp->next = pTop->next;
    pTop->next = temp;
    return true;
}
bool Stack::pop(){
    if(pTop->next == NULL){
        return false;
    }
    SNode* temp = new SNode;
    temp = pTop->next;
    pTop = temp;
    free(temp);
    return true;
}
T Stack::top(){
    T temp;
    temp = pTop->next->data;
    return temp;
}


//template <typename T>
int main(){
    Stack S;
    S.push(114);
    cout << S.pTop->next->data <<endl;
    S.top();
    cout << S.pTop->next->data <<endl;
    S.pop();
    cout << S.pTop->next->data <<endl;
    return 0;
}

三 Stack类的编写(使用模板)

参考链接:https://www.cnblogs.com/0-lingdu/p/12269554.html

        需要更改的地方不多,

1.将开头typedef int T一句移去,在class前添加template <typename T>,T即为未定义的数据类型.注意不加分号.

由于SNode的定义也用到了T,所以我们把该定义也移到class内(这里我存疑,在class内定义typedef我不确定会不会出什么问题,但至少代码不会报错):

template<typename T>
class Stack{
public:
    typedef struct SNode{
            T data;
            struct SNode* next;
        }SNode,*pStack;
    pStack pTop= new SNode;;//SNnode是我们自己创建的新数据类型,与int,float地位一致
    Stack();
    /*使用Stack()为无参构造函数,用于初始化数据域
    构造函数名字必须与类名相同,构造函数前面不需要void等返回类型
    下方Stack(pStack)同样为构造函数,用pStack将Stack初始化,即当输入一个栈时,S即指向该栈.
    */
    Stack(pStack);
    bool empty();
    bool push(T);
    bool pop();
    int length();
    T top();
};

2.在类实现每一句前面都要加template <typename T>,随后在Stack::的::加上<T>,注意是每一句

Stack<T>::Stack(pStack NewStack){
    pTop = NewStack;
}
//这里用带头节点的链表来定义栈,故第一个元素为S->next,为NULL则栈空,pop失败

template <typename T>
bool Stack<T>::empty(){
    if (pTop->next == NULL)return true;
    else return false;
}

至此完成,可以运行下列main函数:

int main(){
    Stack<int> S;
    S.push(114);
    cout << S.pTop->next->data <<endl;
    S.top();
    cout << S.pTop->next->data <<endl;
    S.pop();
    cout << S.pTop->next->data <<endl;
    return 0;
}

        第二行Stack<int>中,"int"可换为任意数据类型,可以回到这偏偏文章开头,我们编写的Stack函数与c++<stack>库使用方法完全相同.本文主要内容到此为止.更进一步,可以将Stack.h头文件与Stack.cpp文件拆开,以供其它文件调用,那些难度不大,也不方便在一篇文章内说明,这里就不展开.

        本人还在学习C++,难免有错误或疏漏,各位佬轻喷(狗头保命)

        感谢阅读,以下是完整代码.

//参考链接:https://www.cnblogs.com/0-lingdu/p/12269554.html
#include<iostream>
using namespace std;

template<typename T>
class Stack{
public:
    typedef struct SNode{
            T data;
            struct SNode* next;
        }SNode,*pStack;
    pStack pTop= new SNode;;//SNnode是我们自己创建的新数据类型,与int,float地位一致
    Stack();
    /*使用Stack()为无参构造函数,用于初始化数据域
    构造函数名字必须与类名相同,构造函数前面不需要void等返回类型
    下方Stack(pStack)同样为构造函数,用pStack将Stack初始化,即当输入一个栈时,S即指向该栈.
    */
    Stack(pStack);
    bool empty();
    bool push(T);
    bool pop();
    int length();
    T top();
};

//类可以将定义与实现分离,以上class定义类,以下代码实现class的各种操作
template <typename T>
Stack<T>::Stack(){
    pTop->next = NULL;
}

template <typename T>
Stack<T>::Stack(pStack NewStack){
    pTop = NewStack;
}
//这里用带头节点的链表来定义栈,故第一个元素为S->next,为NULL则栈空,pop失败

template <typename T>
bool Stack<T>::empty(){
    if (pTop->next == NULL)return true;
    else return false;
}

template <typename T>
bool Stack<T>::push(T n){
    SNode* temp = new SNode;
    temp->data = n;
    temp->next = pTop->next;
    pTop->next = temp;
    return true;
}

template <typename T>
bool Stack<T>::pop(){
    if(pTop->next == NULL){
        return false;
    }
    SNode* temp = new SNode;
    temp = pTop->next;
    pTop = temp;
    free(temp);
    return true;
}

template <typename T>
T Stack<T>::top(){
    T temp;
    temp = pTop->next->data;
    return temp;
}


//template <typename T>
int main(){
    Stack<int> S;
    S.push(114);
    cout << S.pTop->next->data <<endl;
    S.top();
    cout << S.pTop->next->data <<endl;
    S.pop();
    cout << S.pTop->next->data <<endl;
    return 0;
}

标签:定义,temp,为例,pTop,将类,SNode,next,pStack,Stack
From: https://blog.csdn.net/choochah/article/details/142898441

相关文章

  • 在 LaTeX 中,默认的 `enumerate` 环境会输出 “1. 2. 3.“ 这样的编号。如果你想将编号
    在LaTeX中,默认的enumerate环境会输出“1.2.3.”这样的编号。如果你想将编号格式改为(1)(2)(3)这种样式,你可以通过enumerate包进行自定义。在导言区导入enumerate包:\usepackage{enumerate}在enumerate环境中使用\renewcommand来自定义编号格式为带括号的样式......
  • 如何在cnblogs的发文中使用自定义地址作为发文链接
    要知道在cnblogs中发表内容后其默认的链接地址都是一串数字的形式,比如本篇的默认地址:https://www.cnblogs.com/xyz/p/18461898但是为了让发表的内容更有个性化,于是我们可以指定发文内容的链接地址,也就是自定义发文内容的链接地址,具体方法为在发表时指定slug地址,具体如下:如果......
  • Qt自定义一个圆角对话框
    如何得到一个圆角对话框?步骤:1、继承自QDiaglog2、去掉系统自带的边框3、设置背景透明,不设置4个角会有多余的部分出现颜色4、对话框内部添加1个QWidget,给这个widget设置圆角,并添加到布局中让他充满对话框5、后续对话框的所有内容都添加在这个widget里面举例:#ifndefRO......
  • 实验项目3 自定义路由转换器
    实验目的了解Django处理HTTP请求的流程。掌握路由转换器的用法。掌握如何定义和使用自定义路由转换器。实验内容操作1 创建Django项目chapter02(先进入之前创建的虚拟环境(python3.7、有Django))操作2 在项目chapter02中创建应用app01(应用需要激活应用并分配根路由、创建子......
  • Spring Boot 集成 RabbitMQ 自定义 MessageConverter
    1.SpringBoot集成RabbitMQ自定义消息转换器1.1.版本说明1.2.概述1.3.Spring配置1.4.定义常量1.5.配置交换机和队列1.6.配置ObjectMapper1.7.配置MessageConverter1.8.测试1.SpringBoot集成RabbitMQ自定义消息转换器1.1.版本说明构件版......
  • 自定义 http header 名称中带下划线时,可能会被 nginx 忽略删除
    在设计自定义header时,会发现如user_id这样的header无法被后端读取到想来中间有一层nginx搜了一下果然是它的影响,具体情况就不记录了,可以看参考链接。简单记录是因为下划线可能会导致一些兼容性问题,所以nginx默认不允许header名称带下划线,但也允许手动开启。解决方......
  • python量化数据4:茅台为例计算股票日k线涨跌幅
    一、环境pipinstallpandaspipinstallmootdx二、代码#行业业绩轮动公众号首发frommootdx.quotesimportQuotesimportpandasaspdclient=Quotes.factory(market='std')#获取实时行情df=client.bars(symbol='600519',frequency=9,offset=15)#获取最近1......
  • 了解如何实现自定义View
    在Android开发中,自定义View是实现独特UI组件的重要手段。通过自定义View,开发者可以创建出满足特定需求、具有独特外观和行为的UI元素。以下将详细介绍如何实现自定义View,包括基础步骤、关键要点以及最佳实践。一、自定义View的基础步骤1.继承View或其子类首先,你需要创建一......
  • 用自定义功能区完成Excel两种颜色的交错填充
    今天需要用Excel中的填充颜色完成两种颜色的交错填充在excel中,选择一个颜色填充后,再切换到另一个颜色,再点击填充。操作起来会显得比较笨重 于是萌生了一个想法,是否可以通过Excel的自定义功能区,增加一个类似于填充颜色的小方格,把另一种颜色放进去呢?答案是否定的。因为Excel默......
  • 2024.10.11(自定义异常)
    自定义异常当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。自定义异常的步骤定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException如果继承Exception,属于编译异常如果继承RuntimeExc......