当前位置:  开发笔记 > 编程语言 > 正文

这本书的第252页上有错字“ c ++的完整指南”?

如何解决《这本书的第252页上有错字“c++的完整指南”?》经验,为你挑选了1个好方法。

我正在读《 c ++的完整指南》这本书。我认为第252页有错字。因此,我有以下三个文件。

在文件account.h中,

// account.h
// Defining the class Account.     class definition (methods prototypes) is usually put in the header file
// ---------------------------------------------------
#ifndef _ACCOUNT_                                             // if _ACCOUNT_ is not defined
#define _ACCOUNT_

#include 
#include 
using namespace std;


class Account
{
   private:
     string name;
     unsigned long nr;
     double balance;

   public:            //Public interface:
     bool init( const string&, unsigned long, double);
     void display();
};
#endif
// _ACCOUNT_

在account.cpp文件中,

// account.cpp
// Defines methods init() and display().
// ---------------------------------------------------
#include "account.h"             // Class definition
#include 
#include 
using namespace std;
// The method init() copies the given arguments
// into the private members of the class.


bool Account::init(const string& i_name,
                   unsigned long i_nr,
                   double i_balance)
{
    if( i_name.size() < 1)
          return false;          // check data format to make sure it is valid
    name = i_name;
    nr = i_nr;
    balance = i_balance;
    return true;
}

// the method display() outputs private data.
void Account::display()
{
   cout << fixed << setprecision(2)
        << "--------------------------------------\n"
        << "Account holder:" << name << '\n'
        << "Account number:" << nr << '\n'
        << "Account balance:" << balance << '\n'
        << "--------------------------------------\n"
        << endl;
}

最后,在文件account_t.cpp中

// account_t.cpp
// Uses objects of class Account.
// ---------------------------------------------------
#include "account.h"                 // header file which contains class definition; (prototype for member functions)

int main()
{
   Account current1, current2;       // create two instances with name current1, current2

   current1.init("Cheers, Mary", 1234567, -1200.99); 
// have to call the init function to initialize a Account object; init function is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition  
   current1.display();
   // current1.balance += 100;         // Error: private member
   current2 = current1;
   current2.display();

   current2.init("Jones, Tom", 3512347, 199.40);
   current2.display();
   Account& mtr = current1;     // create a reference, which points to object current1
   mtr.display();
   return 0;
}

我认为这是不正确的。因为显然没有办法访问init成员方法和display成员方法,对吗?我希望这不是一个幼稚的问题。

编辑:我试图在文件account_t.cpp中运行主要功能,并获得以下输出。

~$ g++ account_t.cpp
/tmp/ccSWLo5v.o: In function `main':
account_t.cpp:(.text+0x8c): undefined reference to `Account::init(std::__cxx11::basic_string, std::allocator > const&, unsigned long, double)'
account_t.cpp:(.text+0xb6): undefined reference to `Account::display()'
account_t.cpp:(.text+0xd5): undefined reference to `Account::display()'
account_t.cpp:(.text+0x132): undefined reference to `Account::init(std::__cxx11::basic_string, std::allocator > const&, unsigned long, double)'
account_t.cpp:(.text+0x15c): undefined reference to `Account::display()'
account_t.cpp:(.text+0x176): undefined reference to `Account::display()'
collect2: error: ld returned 1 exit status

任何更多的评论,不胜感激。



1> walnut..:

您的询问没有问题。initdisplay声明public中的定义class Account,并与类定义的文件#include中适当编.cpp使用这些方法。

为了使用一个函数,只需要声明它(在包含的头文件的类定义中)。.cpp使用该功能不需要文件中的定义/实现。

每个.cpp函数都是单独编译的(称为翻译单元),之后,每次使用函数(可能只有其声明)的功能(如果需要)都通过函数的范围,名称和签名与其他翻译单元的正确定义链接。这称为链接过程。

C ++入门书籍应解释编译和链接过程的工作方式。

对于g++,有一种简单的方法可以将所有.cpp文件分别编译为翻译单元,然后将它们直接链接在一起:

g++ account_t.cpp account.cpp

您总是需要.cpp像这样将所有内容添加到编译器调用中。(有其他方法,但这是最简单的方法。)

但是,如评论中所述,该程序还有其他问题:

    _ACCOUNT_是一个可能不在#define程序中的保留标识符。保留所有以下划线和大写字母开头的标识符。使用它们会导致未定义的行为。

    using namespace std;是不好的,至少在头文件中使用时,请参见为什么“使用命名空间std”;被认为是不良做法?。

    类具有构造函数。init大多数情况下,不应编写方法。构造函数负责构造和初始化类实例。但是代码中没有使用构造函数。

    绝对不要将钱存储在中double,因为用算术double不精确。您应将整数形式的值存储在最小相关货币单位(例如美分)的维度中。

    #include 头文件中不需要。人们应该避免添加#include不需要的。

    init返回指示初始化成功的布尔值。但是请main不要检查该值。如果某个函数可能因错误值而失败,那么您必须检查该函数返回的错误值,以确保继续执行程序的其余部分是安全的。

这些观点中的某些观点可能是简化初学者程序的借口,具体取决于这本书的内容(尽管200余页应该已经涵盖了很多),但其他方面则没有。


构造函数使用相同功能的示例:

class Account
{
   private:
     string name;
     unsigned long nr;
     double balance;

   public:            //Public interface:
     Account(const string&, unsigned long, double);
     void display();
};
Account::Account(const string& i_name,
                   unsigned long i_nr,
                   double i_balance)
    : name(i_name), nr(i_nr), balance(i_balance)
{
}
int main()
{
   Account current1("Cheers, Mary", 1234567, -1200.99); 
// Create Account instance and initialize private members; constructor is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition  
   current1.display();
   // current1.balance += 100;         // Error: private member
   Account current2 = current1; // Create second Account instance and copy private members from first one
   current2.display();

   current2 = Account("Jones, Tom", 3512347, 199.40); // Replace instance with a copy of a new one
   current2.display();
   Account& mtr = current1;     // create a reference, which points to object current1
   mtr.display();
   return 0;
}

i_name.size() < 1检查(这是古怪写的,为什么不i_name.size() == 0?)将通过从构造抛出一个异常实现:

Account::Account(const string& i_name,
                   unsigned long i_nr,
                   double i_balance)
    : name(i_name), nr(i_nr), balance(i_balance)
{
    if(i_name.size() == 0) {
       throw invalid_argument("Account does not accept empty names!");
    }
}

这需要#include并且是更高级的主题。

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有