C++井字棋setAlls函数失效及头源文件使用、重定义错误疑问
问题解答
1. setAlls函数无法修改游戏棋盘的问题
原因
setAlls的第一个参数采用值传递规则:调用函数时C++会自动生成原gameboard对象的临时副本,函数内所有修改操作都作用在这个副本上,函数执行结束后副本直接销毁,原对象完全没有被改动。
而类成员方法setPointAll是直接操作当前调用它的实例的内部成员变量,所以可以正常修改数值。
修复方案
将setAlls的参数改为左值引用即可直接操作原对象,声明和定义都修改为:
void setAlls(Gameboard& gameboard, char value);
仅需要在参数类型后加&符号即可。
2. 头文件与源文件的使用规范及重定义错误原因
基础使用规范
- 头文件(.h/.hpp) 仅用于存放声明类内容:类定义、函数声明、模板定义、inline函数定义、extern修饰的全局变量声明、宏定义。必须添加头文件保护(
#pragma once或者#ifndef守卫),避免被多次包含导致重定义。
禁止在头文件中存放非inline、非模板的函数实现,以及全局变量的定义,否则多个源文件引用该头文件时,每个编译单元都会生成一份独立的函数/变量定义,链接时直接触发重定义错误。 - 源文件(.cpp) 用于存放实现内容:非inline函数的实现、全局变量的定义、静态类成员的定义。不要在源文件中编写可供其他文件调用的声明,避免跨文件引用时声明不一致。
你当前代码触发重定义的直接原因
Gameboard.cpp存在重复代码:所有类成员方法都被写了两遍,前半段实现了一次构造函数、printBoard、setPoint等方法后,后半段又重复引入头文件并再次实现了一遍所有方法,同一个编译单元内同一个函数被定义两次,直接触发重定义。另外你最后一个getPoint方法还缺失了右大括号。functions.h中直接存放了setAlls的函数实现,且该函数没有加inline修饰,只要有多个源文件引用这个头文件,链接时就会报setAlls重定义。如果要把函数实现放在头文件里,需要给函数加inline修饰,否则要把实现挪到单独的functions.cpp中,仅在头文件保留声明。- 针对Udacity平台要求仅用3个.cpp文件的场景:不需要拆分头文件的情况下,不要在多个.cpp文件中重复定义同一个类、同一个函数,用到的类可以统一在一个位置定义,或者在调用前提前做前向声明即可,重复定义类会直接触发报错。
内容的提问来源于stack exchange,提问作者HarryTra
相关产品推荐
相关产品推荐

