【问题标题】:C++ function make referenceC++ 函数参考
【发布时间】:2014-01-13 02:30:14
【问题描述】:

我正在尝试制作一个银行账户程序:

创建一个具有帐号、PIN 和余额的帐户类。 Acct number 和 PIN 通过构造函数进入。 帐号永远不会改变。 可以更改 PIN,但前提是提供了正确的帐号作为参数。 仅当正确的 PIN 和帐号作为参数(当然,连同新余额一起)提交给此方法时,才能更改余额。 创建一个将帐号和当前余额一起打印的方法。

目前为止:

#include <iostream>
#include <string>
using namespace std;

//account structure
struct account{
    char accountNumber[10];
    char pin[10];
    double balance;
}account1, account2;

int main() {

    //set account info
    account1.accountNumber = 00011;
    account1.pin = 1234;
    account1.balance = 0.00;

    //set account info
    account2.accountNumber = 00022;
    account2.pin = 4321;
    account2.balance = 100.00;

    //program end
    return 0;
}

//function to change account pin
void changePin(char accountNumber, char pin, char newPin)//PROBLEM
{
    if(strcmp(accountNumber.pin, pin) == 0)
    {
        accountNumber.pin = newPin;
    }
    else
    {
        cout << "Account number or password incorrect.";
    }
}

//change account balance
void changeBalance(char number, char pin, double newBalance)//PROBLEM
{
    if((strcmp(account.pin, pin) == 0) && (strcmp(account.accountNumber, number) == 0))
        {
            account.balance = newBalance;
        }
    else
    {
        cout >> "Account number or pin incorrect.";
    }
}

//function to print account number and balance
void printInfo(char accountNumber)//PROBLEM
{
    cout << "Account Number: " << account.accountNumber;
    cout << "Account Balance: " << account.balance;
}

现在我的问题是,我不知道如何在函数中引用我想要的帐户来比较输入的信息是否与当前帐户信息匹配。

编辑: 我的程序差不多完成了,我只是在这里遇到了一个问题:

class Account;
class Account{

public:
    int accountNumber;
    char pin[5];
    double balance;

    void printInfo();
    void changeBalance(int n, char * p, double b);
    void changePin(int n, char * p, char * newPin);
};
void Account::changePin(int n, char * p, char * newPin)
{
    if((n == accountNumber) && (strcmp(p, pin) == 0))
    {
        //pin = newPin;
    }
}

我正在尝试编写一个可以更改 pin 号的函数,但我不知道如何编写分配,因为我不断收到错误。

【问题讨论】:

  • 既然你已经标记了这个c++,那么你想在account对象上使用方法来完成这种事情似乎是合乎逻辑的.这样,您将使用对现有帐户的引用来调用该方法。这听起来合理吗?
  • 您似乎是 C++ 新手。您是一般的编程新手,还是来自不同的语言?用您更熟悉的术语解释可能对我们有所帮助。
  • 我学过一点java,但我刚开始学c++
  • 我不明白您在帐户对象上使用方法的意思。你的意思是 account.changePin()?问题是我不知道如何获取帐户的当前 pin 以进行比较。
  • 要将文本字符复制到字符数组中,请使用strncpy——它是“STRing CoPY,大小为 N 的数组”的缩写。但是,你最好使用std::string 而不是字符数组。

标签: c++ function struct structure account


【解决方案1】:

创建一个帐户类

class 在执行中与struct 非常相似,但在概念上它们有点不同:

c 时代,您可能拥有一些属于同一类的数据(例如帐号、余额、密码),因此您可以使用struct 将它们全部保存在一个包中。您可以将其视为文件柜中的(物理)文件夹——它都在一个地方,但它只是数据的集合,仅此而已。那是struct

为了使用该文件夹,您必须获取该文件夹,查看其中的内容,然后决定如何处理它。文件夹中的数据没有真正的保护。这类似于拥有一堆函数,您可以将struct 的实例传递给这些函数,并且该函数可以修改该结构的内容。这是c 中的工作方式,但没有数据保护,这可能有点乏味,并且希望有更好的东西。

class 有数据和方法。突然之间,它不再是一个可以传递的毫无生气的文件夹。现在它是一个真正的仆从——它拥有数据,但你也可以告诉它为你做一些事情,它知道如何使用自己的数据来完成任务。这样,minion 可以保护数据免受外部干扰,并且仍然可以做有用的工作。

因此,正如@Greg 所建议的那样,在这里定义一个类会是一种更好的方法。您将希望它包含每个帐户唯一的数据,以及将处理该数据的方法(初始化它的构造函数,其他更改 PIN 和余额的方法,可能还有一些 getter 来查看数据 - 或者至少是一些为了调试而打印它)。

通过这种方式,就不需要引用了,但我稍后会谈谈数据类型,因为您似乎也对此感到困惑。

数据类型

让我们看看您的帐户结构:

struct account{
  char accountNumber[10];
  char pin[10];
  double balance;
};

balance 是什么?它是一个浮点数。这意味着它包含一个数字,其中可以有一个小数点。例如,可以是5、3.7、3.1415926535898、-123、-2.34等,但不能是“狗”、“猫”,也不能是字母“q”。

accountNumberpin 是什么?您已将它们创建为字符数组(特别是 10 个字符长)。这意味着什么?好吧,它们可以容纳一个字符块,9 个字符或更少(请记住为空终止符留出空间)。例如,他们可以持有“1”、“2.3”、“1.2.3.4”、“狗”、“猫”、“^&*$^@X”。

请注意,1"1" 之间存在天壤之别。 1 是一个数字。如果我们查看计算机内部的所有 1 和 0,它会以类似 00000000 00000000 00000000 00000001 的形式存储在内存中。我们通常用十六进制写这样的数字,因为它更短,看起来像:0x00000001。它是 32 位长(又名 4 字节)。这是特定于平台的,但这是最常见的,应该足以与文本“1”形成对比:

“1”是两个字符:'1' 和 '\0'(字符 -- 不是数字 -- 一个,以及用于结束字符串的空终止符)。这将在内存中类似于:00110001 00000000 -- 或 int hex:0x3100。请注意,这要短得多(每个字符是一个字节),所以“1”只有 2 个字节,而实际整数是 4 个字节。并且 1 位在不同的位置。 '1' 实际上是十六进制 0x31!

了解字符串和数字之间的区别很重要。基本上,字符串用于文本(或以人类可读格式打印数字),而数字数据类型用于实际的数字工作。

考虑到这一点,您可能需要在这里重新考虑您的数据类型。

标头与来源、声明与定义

C++ 拥有而Java 缺少的东西是头文件。这些有时非常棘手和烦人,但在其他方面也相当有用。撇开这些不谈,我将只关注实际情况。

声明与定义

首先,什么是声明?这是一种告诉编译器“我有东西”的方式。这可能看起来过于基本,但将其与定义进行对比:

定义是告诉编译器“这就是事物的样子”的一种方式。

所以,如果你想创建一个函数,声明所需的东西很少:

int AddTheseNumbers(int a, int b);

这足以告诉编译器AddTheseNumbers,我们现在可以编写使用它的代码。编译器知道:

  • 函数的名称。
  • 函数的返回值 - 因此它知道要为返回分配多少堆栈空间。
  • 参数(两个ints,按值传递) - 因此它知道在调用函数之前要压入堆栈的数量。

但请注意编译器知道的:函数实际做了什么。那是因为编译器不需要知道这一点。是的,我们最终需要它(显然,没有它程序就无法运行),但生成 Foo.obj 文件不需要它(链接器将在生成 Program.exe 时使用它)。

现在让我们看一下该函数的定义

int AddTheseNumbers(int a, int b) {
  return a + b;
}

它和声明是一样的签名——编译器/链接器就是这样知道我们定义了什么,现在我们有了函数的bodybody 是定义。

标头用于声明,源用于定义

所以,我们可以创建Simple.h

int AddTheseNumbers(int a, int b);

还有Simple.cpp 和:

int AddTheseNumbers(int a, int b) {
  return a + b;
}

然后我们可以编译创建Simple.obj

此外,我们可以通过以下方式创建MyProgram.cpp

#include "Simple.h"  // Hey look, I can now use my other file!

int main(int argc, char** argv) {
  std::cout << "Adding 3 + 5: " << AddTheseNumbers(3, 5) << std::endl;
  return 0;
}

我们可以把它编译成MyProgram.obj。然后我们使用 linker 将这些 obj 文件链接在一起,生成 MyProgram.exe,然后我们可以运行它。

使用类会稍微复杂一些。简而言之,对于 Foo 的类,我们可以这样做:

class Foo;

这称为前向声明,它只是告诉编译器“有一个名为 Foo 的结构,但我不知道其中有什么”。这对于通过引用或指针传递Foo 的实例很有用,但实际上您不能对Foo 执行任何操作,因为您不知道其中的内容。

class Foo {
  int x;
 public:
  int getX();
};

这是Foo 的完整声明。编译器知道其中包含什么数据(计算Foo 的完整大小所必需的)和方法签名(就像上面的函数声明一样)。这足以编写代码:

Foo f;
std::cout << f.getX();

它会编译,因为编译器知道为Foo分配多少内存,以及如何与它交互。它不知道getX 做了什么,但它不在乎——那是链接器的工作。

int Foo::getX() {
  return x;
}

这是FoogetX 方法的定义。它是相同的签名(返回 int,无参数),并且它的范围为 Foo 本身。请注意,此方法可以简单地使用x——该方法本身带有Foo 的实例,因此它可以访问同一Foo 实例中的所有内容。

【讨论】:

  • 我现在有点明白了。另一个问题是,我是否只是将结构中的内容放入新的 cpp 文件中?我该如何处理 .h 文件?
  • 好问题。快速回答:.h 文件用于声明,.cpp 文件用于定义。我会在我的回答中提供更多细节。
  • 对于您之前的长答案,所以我应该将我的数据类型更改为 int?问题是如果我希望我的帐号/密码以零开头。 00123,如果它是 int 而不是 string,程序是否会读取/打印为 123?
  • 谢谢你非常详细的回答顺便说一句。我了解其中的大部分内容,并将尝试使用它来解决。
  • @user3188716 - 这是关于前导零和 PIN 的完美观点。正确,int 会很糟糕。 char[] 可以解决这个问题,但您可能需要额外的逻辑来强制执行仅数字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-18
  • 2018-09-20
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 2010-12-12
  • 2018-10-01
相关资源
最近更新 更多