Virtual error ue4 c++

Im trying to make my character sprint online! If im doing something wrong please let me know and explain! Im not good with online and in trying to really get the hang of it. I defined all the virtual functions i have and tbh, idk what makes a virtual function a virtual function but i just tried making all the ones i made virtual functions and eliminating one by one but i cant seem to find the issue. Im so frustrated! I defined everything and its still giving me a problem! Ive also followed multiple tutorials and i still get the same outcome. i thought i understood everything but i guess not… i feel defeated. Thank you in advance

Undefined symbols for architecture x86_64:
  "vtable for ASprintHealthTestCharacter", referenced from:
      ASprintHealthTestCharacter::ASprintHealthTestCharacter() in SprintHealthTestCharacter.cpp.o
      ASprintHealthTestCharacter::ASprintHealthTestCharacter(FObjectInitializer const&) in SprintHealthTestCharacter.cpp.o
      ASprintHealthTestCharacter::ASprintHealthTestCharacter(FObjectInitializer const&) in SprintHealthTestCharacter.cpp.o
      UObject* InternalVTableHelperCtorCaller<ASprintHealthTestCharacter>(FVTableHelper&) in SprintHealthTestCharacter.gen.cpp.o
      ASprintHealthTestCharacter::ASprintHealthTestCharacter(FVTableHelper&) in SprintHealthTestCharacter.gen.cpp.o
      ASprintHealthTestCharacter::ASprintHealthTestCharacter(FVTableHelper&) in SprintHealthTestCharacter.gen.cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

.h

#pragma once

#include "Engine.h"

#include "GameFramework/Character.h"

#include "Net/UnrealNetwork.h"

#include "SprintHealthTestCharacter.generated.h"

UCLASS(config=Game)
class ASprintHealthTestCharacter : public ACharacter
{

	GENERATED_UCLASS_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	ASprintHealthTestCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;
    
    UPROPERTY(EditAnywhere,ReplicatedUsing=GetMaxHealth, Category = Attributes)
    float Health;
    
    UPROPERTY(Replicated)
    TArray<uint32> IntegerArray;
    
    UFUNCTION(Server,Reliable,WithValidation)
    void ServerSprint();
    
    UFUNCTION(Client,Reliable)
    void ClientSprint();
    
    UFUNCTION(BlueprintCallable,Category = Attributes)
    virtual void GetMaxHealth();
    
    void Sprint();
    
    void SprintEnd();
    
    bool bIsSprinting = true;
   
    
protected:

	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:

	// APawn interface

	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	// End of APawn interface

    //VIRTUAL VOIDS
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;
    
public:

	/** Returns CameraBoom subobject **/

	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }

	/** Returns FollowCamera subobject **/

	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};

.cpp

#include "SprintHealthTestCharacter.h"

#include "HeadMountedDisplayFunctionLibrary.h"

#include "Camera/CameraComponent.h"

#include "Components/CapsuleComponent.h"

#include "Components/InputComponent.h"

#include "GameFramework/CharacterMovementComponent.h"

#include "GameFramework/Controller.h"

#include "GameFramework/SpringArmComponent.h"

#include "Net/UnrealNetwork.h"

//////////////////////////////////////////////////////////////////////////
// ASprintHealthTestCharacter

ASprintHealthTestCharacter::ASprintHealthTestCharacter(const FObjectInitializer& ObjectIntializer)
{
    bReplicates = true;

    bReplicateMovement = true;

	// Set size for collision capsule

	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input

	BaseTurnRate = 45.f;

	BaseLookUpRate = 45.f;


	// Don't rotate when the controller rotates. Let that just affect the camera.

	bUseControllerRotationPitch = false;

	bUseControllerRotationYaw = false;

	bUseControllerRotationRoll = false;


	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	

	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate

	GetCharacterMovement()->JumpZVelocity = 600.f;

	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)

	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));

	CameraBoom->SetupAttachment(RootComponent);

	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	

	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller


	// Create a follow camera

	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));

	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);` // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation

	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}

//////////////////////////////////////////////////////////////////////////
// Input

void ASprintHealthTestCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);
	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);

	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &ASprintHealthTestCharacter::MoveForward);

	PlayerInputComponent->BindAxis("MoveRight", this, &ASprintHealthTestCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);

	PlayerInputComponent->BindAxis("TurnRate", this, &ASprintHealthTestCharacter::TurnAtRate);

	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);

	PlayerInputComponent->BindAxis("LookUpRate", this, &ASprintHealthTestCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &ASprintHealthTestCharacter::TouchStarted);

	PlayerInputComponent->BindTouch(IE_Released, this, &ASprintHealthTestCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ASprintHealthTestCharacter::OnResetVR);

    //Sprint
    PlayerInputComponent->BindAction("Sprint", IE_Pressed,this, &ASprintHealthTestCharacter::Sprint);

    PlayerInputComponent->BindAction("Sprint", IE_Released,this, &ASprintHealthTestCharacter::SprintEnd);


}


void ASprintHealthTestCharacter::OnResetVR()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}

void ASprintHealthTestCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void ASprintHealthTestCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void ASprintHealthTestCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void ASprintHealthTestCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void ASprintHealthTestCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void ASprintHealthTestCharacter::MoveRight(float Value)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}
void ASprintHealthTestCharacter::GetLifetimeReplicatedProps(TArray &OutLifetimeProps)const {
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    DOREPLIFETIME(ASprintHealthTestCharacter, IntegerArray);

    DOREPLIFETIME(ASprintHealthTestCharacter, Health);
}

bool ASprintHealthTestCharacter::ServerSprint_Validate(){


    return true;
}
void ASprintHealthTestCharacter::ServerSprint_Implementation(){

    Sprint();
}

void ASprintHealthTestCharacter::Sprint(){

    if (Role < ROLE_Authority){


        ServerSprint();

        if (bIsSprinting == true)

                 GetCharacterMovement()->MaxWalkSpeed = 1000.0f;

            }
    }

void ASprintHealthTestCharacter::SprintEnd(){
    
}

void ASprintHealthTestCharacter::BeginPlay(){

    Super::BeginPlay();
    
}

void ASprintHealthTestCharacter::Tick(float DeltaTime){

    Super::Tick(DeltaTime);
}

Don’t know if it will fix your error but if you look into how UE creates the character for the third person cpp project they are not implementing

ASprintHealthTestCharacter::ASprintHealthTestCharacter(const FObjectInitializer& ObjectIntializer)

but

ASprintHealthTestCharacter::ASprintHealthTestCharacter()

on the make a multiplayer sprint,
you should look into how the jump is implemented
your current implementation will screw up player movement prediction,
to handle that correctly you will need to add sprint to your version of the UCharacterMovementComponent and into the FSavedMove_Character class

that’s the only tutorial on that topic that I have found so far

you forgot to define"GetMaxHealth();" in your cpp file

as it return nothing for now, du comment it in your H file would do the trick.

ps: it’s written on the error log you posted :

 NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.

I actually ended up removing that part and renaming it and it still doesn’t work :confused: so it’s not that. I realized I missed that after the post I should’ve updated it but I had gotten caught up on something!

Thank you! I will look at this later!

and what’s the new error ?