C++中以引用传递对象作为类参数的问题求助
问题分析与解决方案
问题根源
你遇到的核心问题是对象拷贝导致的两个独立Pawn实例:
- 当调用
board.addNewPawn(pawn)时,函数参数采用值传递,这会创建一个pawn的副本并赋值给Board内部的m_pawn。 - 主函数中的
pawn和Board中的m_pawn是完全独立的对象,地址不同,因此修改主函数中pawn的位置不会同步到Board的m_pawn。
解决方案1:使用指针共享同一个对象
通过让Board持有指向主函数中Pawn对象的指针,确保两者操作的是同一个实例。
步骤1:修改Board.h
将私有成员m_pawn改为指针类型,并更新函数签名:
#ifndef BOARD #define BOARD #include<vector> #include "Pawn.h" class Board { public: Board(int x, int y); void initBoard(); void displayBoard(); void addNewPawn(Pawn* pawn); // 修改为指针参数 private: std::vector<std::vector<char>> m_board; int m_xsize; int m_ysize; Pawn* m_pawn; // 改为指针类型 }; #endif
步骤2:修改Board.cpp
- 初始化指针为空,避免悬空指针
- 更新
addNewPawn函数直接赋值指针 - 在
displayBoard中使用->访问指针成员:
#include <iostream> #include <vector> #include "Board.h" using namespace std; Board::Board(int x, int y): m_xsize(x), m_ysize(y), m_pawn(nullptr) // 初始化指针为空 { } // 保留initBoard函数不变 void Board::initBoard() { for (int x=0; x<m_xsize; x++) { vector<char> newline(m_ysize); m_board.push_back(newline); } for (int x = 0; x < m_xsize; x++) { for (int y = 0; y < m_ysize; y++) { if (x == 0 || y == 0 || x == m_xsize - 1 || y == m_ysize - 1) { m_board[x][y] = '*'; } else { m_board[x][y] = ' '; } } } } void Board::displayBoard() { if (m_pawn == nullptr) return; // 防止空指针崩溃 cout << "board pawn address " << m_pawn << endl; m_board[m_pawn->getXpos()][m_pawn->getYpos()] = 'o'; // 使用->访问成员 cout << "display " << m_pawn->getXpos() << " " << m_pawn->getYpos() << endl; for (int x = 0; x < m_xsize; x++) { for (int y = 0; y < m_ysize; y++) { cout << m_board[x][y]; } cout << endl; } } void Board::addNewPawn(Pawn* pawn) { m_pawn = pawn; // 直接赋值指针,共享同一个对象 }
步骤3:修改main.cpp
传递pawn的地址给addNewPawn:
#include <iostream> #include "Board.h" #include "Pawn.h" #include <conio.h> using namespace std; int main() { Pawn pawn{ 1, 1 }; Board board{ 20, 20 }; board.addNewPawn(&pawn); // 传递指针 board.initBoard(); board.displayBoard(); char input; do { input = _getch(); int xshift = 0; int yshift = 0; if (input == 'z') { yshift = -1; } else if (input == 'q') { xshift = -1; } else if (input == 's') { yshift = 1; } else if(input == 'd') { xshift = 1; } cout << "pawn address " << &pawn << endl; pawn.movePawn(xshift, yshift); board.displayBoard(); }while (input != 'x'); }
解决方案2:使用引用共享同一个对象
引用是另一种共享对象的方式,比指针更安全(不会有空指针问题),但需要在Board构造时就绑定到目标对象。
步骤1:修改Board.h
将私有成员改为引用类型,并调整构造函数参数:
#ifndef BOARD #define BOARD #include<vector> #include "Pawn.h" class Board { public: Board(int x, int y, Pawn& pawn); // 添加Pawn引用参数 void initBoard(); void displayBoard(); private: std::vector<std::vector<char>> m_board; int m_xsize; int m_ysize; Pawn& m_pawn; // 改为引用类型 }; #endif
步骤2:修改Board.cpp
在构造函数中初始化引用,并更新displayBoard(无需addNewPawn函数):
#include <iostream> #include <vector> #include "Board.h" using namespace std; Board::Board(int x, int y, Pawn& pawn): m_xsize(x), m_ysize(y), m_pawn(pawn) // 初始化引用 { } // 保留initBoard函数不变 void Board::initBoard() { for (int x=0; x<m_xsize; x++) { vector<char> newline(m_ysize); m_board.push_back(newline); } for (int x = 0; x < m_xsize; x++) { for (int y = 0; y < m_ysize; y++) { if (x == 0 || y == 0 || x == m_xsize - 1 || y == m_ysize - 1) { m_board[x][y] = '*'; } else { m_board[x][y] = ' '; } } } } void Board::displayBoard() { cout << "board pawn address " << &m_pawn << endl; m_board[m_pawn.getXpos()][m_pawn.getYpos()] = 'o'; // 仍使用.访问成员 cout << "display " << m_pawn.getXpos() << " " << m_pawn.getYpos() << endl; for (int x = 0; x < m_xsize; x++) { for (int y = 0; y < m_ysize; y++) { cout << m_board[x][y]; } cout << endl; } }
步骤3:修改main.cpp
创建Board时直接传入pawn的引用:
#include <iostream> #include "Board.h" #include "Pawn.h" #include <conio.h> using namespace std; int main() { Pawn pawn{ 1, 1 }; Board board{ 20, 20, pawn }; // 传入引用 board.initBoard(); board.displayBoard(); char input; do { input = _getch(); int xshift = 0; int yshift = 0; if (input == 'z') { yshift = -1; } else if (input == 'q') { xshift = -1; } else if (input == 's') { yshift = 1; } else if(input == 'd') { xshift = 1; } cout << "pawn address " << &pawn << endl; pawn.movePawn(xshift, yshift); board.displayBoard(); }while (input != 'x'); }
注意事项
- 使用指针时,确保
Pawn对象的生命周期长于Board对象(这里主函数中的pawn先创建,后销毁,符合要求)。 - 使用引用时,引用一旦绑定就无法更改,因此
Board必须从构造时就绑定到目标Pawn。 - 两种方案都能实现同一个对象共享,解决位置不同步的问题,可根据你的代码结构选择。
内容的提问来源于stack exchange,提问作者Willy Lutz
相关产品推荐
相关产品推荐

