为什么函数参数的行为类似于变量声明?
Why is a function parameter behaving like a variable declaration?
我在使用 Unreal 和 运行 时出现了一些奇怪的错误。我最终发现只需重命名我的函数参数就可以解决问题。这是完整的 header 和 class。问题是 InitCard
函数:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/StaticMeshComponent.h"
#include "Playing_Card.generated.h"
UCLASS()
class BLACKJACK_API APlaying_Card : public AActor
{
GENERATED_BODY()
public:
enum Suit { HEARTS = 0, DIAMONDS = 1, CLUBS = 2, SPADES = 3, UNASSIGNED = 4 };
Suit suit = Suit::UNASSIGNED;
// Sets default values for this actor's properties
APlaying_Card();
int rank;
int value;
void InitCard(int rank, Suit suit);
FString faceStr = "";
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* mesh;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
Playing_Card.cpp:
#include "Playing_Card.h"
int rank = 0;
int value = 0;
// Sets default values
APlaying_Card::APlaying_Card()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("mesh"));
RootComponent = mesh;
mesh->SetScalarParameterValueOnMaterials(TEXT("card_index"), 4);
}
void APlaying_Card::InitCard(int rank, Suit suit)
{
this->rank = rank;
this->suit = suit;
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
// Called when the game starts or when spawned
void APlaying_Card::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlaying_Card::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
这给出了错误:
error C4458: declaration of 'rank' hides class member
但是,如果我更改函数参数名称(下面发布的函数),代码编译时不会出错。
/// It works! Just by changing parameter names (note: I still use this->rank)
void APlaying_Card::InitCard(int cardRank, Suit cardSuit)
{
this->rank = cardRank;
this->suit = cardSuit;
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
第一次尝试使用名称时出现错误的原因是什么?
原代码中,全局变量rank
/suit
、class成员rank
/suit
、参数rank
/suit
都在 InitCard()
的范围内。那么您希望编译器在语句 this->rank = rank; this->suit = suit;
的右侧使用哪些?它不会是 class 成员,而是函数参数,因为它们在本地范围内。编译器会警告您这一点,因为它们与 class 成员同名。
删除全局变量并重命名参数,避免了任何歧义。因此,使用其 member initialization list 在其构造函数中初始化 class,而不是单独的 Init
方法:
UCLASS()
class BLACKJACK_API APlaying_Card : public AActor
{
...
public:
...
APlaying_Card(int rank, Suit suit);
...
};
APlaying_Card::APlaying_Card(int rank, Suit suit) :
rank(rank), suit(suit) // <-- no ambiguity here!
{
...
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
不是因为参数的行为像一个变量声明(尽管它们只是初始化方式不同),而是因为只是名称重用(它可能不仅仅是一个已经存在的变量的名称).
在 C++ 语言方面,按照最初的方式命名参数是完全正确的,但在代码设计方面很容易出错,因为很容易误用名称,从而得到与预期不同的结果。
最初,C4458 是一个警告,编译器会通过该警告通知您您做了这种容易出错的事情,但不是错误 - 因此通常它不会阻止成功编译程序;但问题的症结在于您的编译器将警告视为错误,它必须根据相应的编译器设置发生;如果需要,您可以关闭它。
我在使用 Unreal 和 运行 时出现了一些奇怪的错误。我最终发现只需重命名我的函数参数就可以解决问题。这是完整的 header 和 class。问题是 InitCard
函数:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/StaticMeshComponent.h"
#include "Playing_Card.generated.h"
UCLASS()
class BLACKJACK_API APlaying_Card : public AActor
{
GENERATED_BODY()
public:
enum Suit { HEARTS = 0, DIAMONDS = 1, CLUBS = 2, SPADES = 3, UNASSIGNED = 4 };
Suit suit = Suit::UNASSIGNED;
// Sets default values for this actor's properties
APlaying_Card();
int rank;
int value;
void InitCard(int rank, Suit suit);
FString faceStr = "";
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* mesh;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
Playing_Card.cpp:
#include "Playing_Card.h"
int rank = 0;
int value = 0;
// Sets default values
APlaying_Card::APlaying_Card()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("mesh"));
RootComponent = mesh;
mesh->SetScalarParameterValueOnMaterials(TEXT("card_index"), 4);
}
void APlaying_Card::InitCard(int rank, Suit suit)
{
this->rank = rank;
this->suit = suit;
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
// Called when the game starts or when spawned
void APlaying_Card::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlaying_Card::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
这给出了错误:
error C4458: declaration of 'rank' hides class member
但是,如果我更改函数参数名称(下面发布的函数),代码编译时不会出错。
/// It works! Just by changing parameter names (note: I still use this->rank)
void APlaying_Card::InitCard(int cardRank, Suit cardSuit)
{
this->rank = cardRank;
this->suit = cardSuit;
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
第一次尝试使用名称时出现错误的原因是什么?
原代码中,全局变量rank
/suit
、class成员rank
/suit
、参数rank
/suit
都在 InitCard()
的范围内。那么您希望编译器在语句 this->rank = rank; this->suit = suit;
的右侧使用哪些?它不会是 class 成员,而是函数参数,因为它们在本地范围内。编译器会警告您这一点,因为它们与 class 成员同名。
删除全局变量并重命名参数,避免了任何歧义。因此,使用其 member initialization list 在其构造函数中初始化 class,而不是单独的 Init
方法:
UCLASS()
class BLACKJACK_API APlaying_Card : public AActor
{
...
public:
...
APlaying_Card(int rank, Suit suit);
...
};
APlaying_Card::APlaying_Card(int rank, Suit suit) :
rank(rank), suit(suit) // <-- no ambiguity here!
{
...
if (rank == 1)
{
value = rank; //todo: find a way to make Ace 1 or 11.
faceStr = "Ace";
}
else if (rank <= 10)
{
value = rank;
faceStr = FString::FromInt(rank);
}
else if (rank == 11)
{
value = 10;
faceStr = "Jack";
}
else if (rank == 12)
{
value = 10;
faceStr = "Queen";
}
else if (rank == 13)
{
value = 10;
faceStr = "King";
}
}
不是因为参数的行为像一个变量声明(尽管它们只是初始化方式不同),而是因为只是名称重用(它可能不仅仅是一个已经存在的变量的名称).
在 C++ 语言方面,按照最初的方式命名参数是完全正确的,但在代码设计方面很容易出错,因为很容易误用名称,从而得到与预期不同的结果。
最初,C4458 是一个警告,编译器会通过该警告通知您您做了这种容易出错的事情,但不是错误 - 因此通常它不会阻止成功编译程序;但问题的症结在于您的编译器将警告视为错误,它必须根据相应的编译器设置发生;如果需要,您可以关闭它。