我的教授给了我们这堂课,并告诉我们它不会编译。他说,捐赠者阵列会与构造者发生冲突。那么......为什么会这样?
我认为Donor
数组的名称可能会这样做,但它不应该是问题,因为成员数组donor
的名称区分大小写,因此不同于班级名称。
以下是代码:
#ifndef DONORS_H
#define DONORS_H
#include <string>
#include "name.h"
#include "donor.h"
using namespace std;
const int
DONORS_LOAD_ERROR = 1,
DONORS_UPDATE_ERROR = 2,
DONORS_ADD_ERROR = 3;
const int MAX_DONORS = 100;
class Donors {
public:
Donors() : size(0) {}
void load(string filename);
int getSize() {return size;}
int find(Name name);
int add(Name name);
int add(Name name, Donation donation, int ytd);
void processDonation(Name name, Donation donation);
void update(string filename);
void print();
private:
Donor donorsList[MAX_DONORS];
int size;
};
#endif
教授写道:
在这个版本中,我们采用了版本2,添加了构造函数,并最大化了对象的使用。
但是,构造函数的引入打破了Donors类中数组数据成员的声明; 因此,这个版本没有编译!!!!
我和同学一直在讨论这件事,我们都很难过。这个C ++类有什么用?
修改
编译器消息如下所示:
我刚刚想到Donor类有一个构造函数。因为我们没有用十英尺的极点触及矢量,我们究竟应该如何编译它?
EDIT2:
这是捐赠者类:
#ifndef DONOR_H
#define DONOR_H
#include "name.h"
#include "donation.h"
using namespace std;
class Donor {
public:
Donor(Name n, Donation ld=Donation(0, 0), int y=0) : name(n), lastDonation(ld), ytd(y) {}
Name getName() {return name;}
Donation getLastDonation() {return lastDonation;}
int getYtd() {return ytd;}
void processDonation(Donation d);
private:
Name name;
Donation lastDonation;
int ytd;
};
#endif
答案 0 :(得分:5)
如果没有Donor
类的定义很难说,但我的猜测是他在Donor
类中添加了一个带参数的构造函数,因此它不再具有隐式默认构造函数
但是现在,如果没有默认构造函数,那是一个可以不带参数调用的构造函数,就不能声明这种类型的数组,因为没有办法传递所需的参数!
答案 1 :(得分:3)
我猜是类Donor
(你没有包含)没有默认的构造函数。如果是这样,您将收到编译器错误,因为这一行:
Donor donorsList[MAX_DONORS];
将尝试使用Donor
没有的构造函数 - 无参数。
如果您遇到教师向您展示的错误,它将帮助您在课程中做得更好。然后,当你在现实生活中体验它们时,你会认出它们。如果你要学习C ++,那么“我和一个朋友看过这个并且应该编译得很好”的策略永远不会替代尝试编译它并看到你得到的错误。
答案 2 :(得分:0)
您需要包含class Donor
的定义。
从它的外观来看,我猜想class Donor
有一个非默认的构造函数,i。即带有一个或多个参数的构造函数。在这种情况下,编译器不会生成class Donor
的默认构造函数,您必须自己定义它。
创建donorsList
需要默认构造函数,因为在创建对象数组时,会为每个对象调用默认构造函数。
答案 3 :(得分:0)
考虑第一个Donors
类:
#ifndef DONORS_H
#define DONORS_H
#include <string>
#include "name.h"
#include "donor.h"
目前为止确定。
using namespace std;
不!永远不要将using namespace std;
放在标题中的全局命名空间中。作者(你的教授)几乎可以保证愚蠢的名字冲突,比如编译器在一些糟糕的用户代码中抱怨distance
。
const int
DONORS_LOAD_ERROR = 1,
DONORS_UPDATE_ERROR = 2,
DONORS_ADD_ERROR = 3;
const int MAX_DONORS = 100;
这些都是坏名字。保留呼叫所有大写的宏名称。但是请将它们用于宏名称。
另外,最好使用enum
来表示这些常量。
此外,更好地使用例外进行故障报告。
class Donors {
public:
Donors() : size(0) {}
void load(string filename);
最好通过引用string
来传递const
参数。
int getSize() {return size;}
此方法应为const
。
此外,虽然前缀get
在某些语言(例如Java和C#)中具有实际优势,这些语言支持自省(因此基于内省的工具),但在C ++中,它只是愚蠢的冗长 - 在大多数情况下,并且在这种情况。
最好称之为mathod name
。
指南:考虑调用代码的可读性。
int find(Name name);
最好将name
参数作为对const
的引用传递。
int add(Name name);
最好将name
参数作为对const
的引用传递。
int add(Name name, Donation donation, int ytd);
最好将name
和donation
参数作为对const
的引用传递。
名称ytd
非常糟糕。很难猜出它意味着什么。
void processDonation(Name name, Donation donation);
最好将name
和donation
参数作为对const
的引用传递。
界面含糊不清:add
和process
之间有什么区别?
void update(string filename);
最好将name
参数作为对const
的引用传递。
此方法的名称不好。
几乎不可能猜出这种方法的作用。
void print();
这种方法到底应该打印什么样的格式?
private:
Donor donorsList[MAX_DONORS];
此声明要求Donor
具有可以不带参数调用的构造函数,默认构造函数。
int size;
};
#endif
考虑第二个Donor
类:
#ifndef DONOR_H
#define DONOR_H
#include "name.h"
#include "donation.h"
目前为止确定。
using namespace std;
不!永远不要将using namespace std;
放在标题中的全局命名空间中。作者(你的教授)几乎可以保证愚蠢的名字冲突,比如编译器在一些糟糕的用户代码中抱怨distance
。
class Donor {
public:
Donor(Name n, Donation ld=Donation(0, 0), int y=0) : name(n), lastDonation(ld), ytd(y) {}
y
和ytd
是坏名字。在这一点上无法猜测它们的含义。
ld
是个坏名字。
最好通过引用Name
来传递Donation
和const
参数。
注意:当存在用户声明的构造函数(例如上面的构造函数)时,默认构造函数不会自动生成。
Name getName() {return name;}
此方法应为const
。
此外,虽然前缀get
在某些语言(例如Java和C#)中具有实际优势,这些语言支持自省(因此基于内省的工具),但在C ++中,它只是愚蠢的冗长 - 在大多数情况下,并且在这种情况。
最好称之为mathod name
。
指南:考虑调用代码的可读性。
Donation getLastDonation() {return lastDonation;}
见上面的评论。
int getYtd() {return ytd;}
见上面的评论。
void processDonation(Donation d);
最好通过引用const
传递参数。
private:
Name name;
Donation lastDonation;
int ytd;
};
#endif
简而言之,Donors
类要求Donor
具有默认构造函数,但由于Donor
具有用户声明的构造函数,因此不会生成默认构造函数。
一种解决方法是用std::vector
或其他集合替换简单数组,例如
std::vector<Donor> donors_;
或
std::map< std::string, Donor > donors_;