C++中如何将对象作为函数参数?自定义栈类调用疑问
嘿,我来帮你搞定这两件事——先实现你需要的模板栈类,再给你讲清楚C++里对象作为函数参数传递的几种方式,包你明白~
1. 实现模板Stack类
首先咱们来写符合你要求的Stack模板类,包含栈的核心操作:压栈、弹栈、取栈顶、判断空这些。我用vector作为底层存储,因为它的push_back和pop_back效率很高,实现起来也简单:
#include <iostream> #include <tuple> #include <vector> #include <stdexcept> // 用于抛出越界异常 template<typename T> class Stack { private: std::vector<T> elements; // 用vector存栈元素 public: // 默认构造、析构函数,编译器自动生成就行 Stack() = default; ~Stack() = default; // 压栈操作,和你用的Push_back名字保持一致 void Push_back(const T& item) { elements.push_back(item); } // 重载一个支持移动语义的版本,优化性能(可选但实用) void Push_back(T&& item) { elements.push_back(std::move(item)); } // 弹栈操作,栈空时给个提示 void Pop() { if (!IsEmpty()) { elements.pop_back(); } else { std::cerr << "栈是空的,没法弹栈!" << std::endl; } } // 获取栈顶元素,栈空时抛出异常(比直接崩溃友好) T& Top() { if (!IsEmpty()) { return elements.back(); } else { throw std::out_of_range("栈是空的,没有栈顶元素!"); } } // 重载const版本的Top,方便给const对象用 const T& Top() const { if (!IsEmpty()) { return elements.back(); } else { throw std::out_of_range("栈是空的,没有栈顶元素!"); } } // 判断栈是否为空 bool IsEmpty() const { return elements.empty(); } // 获取栈的大小 size_t Size() const { return elements.size(); } };
2. C++中对象作为函数参数的传递方式
C++里传递对象主要有三种方式,咱们结合你的Stack对象逐一说明:
2.1 值传递
简单说就是把对象拷贝一份传给函数,函数里操作的是这个副本,完全不会影响原对象。比如:
void read_command(Stack<std::tuple<std::string, int, int, int, int>> stack) { // 这里的stack是main里S的拷贝,改它和原S没关系 stack.Push_back(std::make_tuple("test", 5,6,7,8)); }
⚠️ 缺点:如果栈里存了大量元素,拷贝的开销会很大,效率很低,一般除非你特意要操作副本,否则别用这种方式。
2.2 引用传递
这是最常用的方式——传递对象的引用,函数里直接操作原对象本身。又分两种:
- 非const引用:允许修改原对象,适合你需要在函数里操作栈(比如压栈、弹栈)的场景:
void read_command(Stack<std::tuple<std::string, int, int, int, int>>& stack) { // 这里的操作会直接作用到main里的S stack.Push_back(std::make_tuple("hello", 10,20,30,40)); std::cout << std::get<0>(stack.Top()) << " "; } - const引用:如果函数只需要读取栈的内容,不需要修改,就用const引用,既安全又避免拷贝:
void print_stack(const Stack<std::tuple<std::string, int, int, int, int>>& stack) { // 这里只能调用const成员函数,比如Top()的const版本、IsEmpty() if (!stack.IsEmpty()) { std::cout << std::get<0>(stack.Top()) << std::endl; } }
✅ 优点:没有拷贝开销,效率高,还能直接操作原对象(非const引用),是日常开发的首选。
2.3 指针传递
传递对象的指针,本质和引用类似,但语法上要用到->访问成员,还要注意空指针的问题:
void read_command(Stack<std::tuple<std::string, int, int, int, int>>* stack) { if (stack != nullptr) { // 先判断指针是不是空的,避免崩溃 stack->Push_back(std::make_tuple("test", 5,6,7,8)); } } // 调用的时候要传对象的地址 read_command(&S);
这种方式现在用得不如引用多,因为引用更安全(不会有空引用的问题,只要你传递的是合法对象)。
完整可运行示例
把上面的代码整合起来,你可以直接运行:
#include <iostream> #include <tuple> #include <vector> #include <stdexcept> template<typename T> class Stack { private: std::vector<T> elements; public: Stack() = default; ~Stack() = default; void Push_back(const T& item) { elements.push_back(item); } void Push_back(T&& item) { elements.push_back(std::move(item)); } void Pop() { if (!IsEmpty()) { elements.pop_back(); } else { std::cerr << "栈是空的,没法弹栈!" << std::endl; } } T& Top() { if (!IsEmpty()) { return elements.back(); } else { throw std::out_of_range("栈是空的,没有栈顶元素!"); } } const T& Top() const { if (!IsEmpty()) { return elements.back(); } else { throw std::out_of_range("栈是空的,没有栈顶元素!"); } } bool IsEmpty() const { return elements.empty(); } size_t Size() const { return elements.size(); } }; void read_command(Stack<std::tuple<std::string, int, int, int, int>>& stack) { stack.Push_back(std::make_tuple("hello", 10, 20, 30, 40)); std::cout << std::get<0>(stack.Top()) << " "; } int main() { Stack<std::tuple<std::string, int, int, int, int>> S; S.Push_back(std::make_tuple("cabs", 1, 2, 3, 4)); std::cout << std::get<0>(S.Top()) << " "; read_command(S); std::cout << std::endl; return 0; }
运行后会输出:cabs hello ,完全符合你的预期。
内容的提问来源于stack exchange,提问作者M.Ritz
相关产品推荐
相关产品推荐

