C++ 的问题构造函数
编辑:这个问题出现了,我想我答对了!去堆栈溢出吧!! :D
我即将进行考试,去年考试的问题之一是发现以下构造函数的实现问题并编写一个更正的构造函数。
Rectangle::Rectangle(string col, int len, int br)
{
setColour(col);
length =len;
breadth=br;
}
类定义如下:
class Polygon
{
public:
Polygon(string col="red");
void printDetails(); // prints colour only
virtual double getArea()=0;
void setColour(string col);
private:
string colour;
};
class Rectangle : public Polygon
{
public:
Rectangle(string, int, int);
void printDetails(); // prints colour and area
// for part 3, delete the line below
double getArea();
private:
int length;
int breadth;
};
我已将代码写入编译器并且运行良好。我猜问题与继承有关,因为 string color;
是私有的,但 setColour
是公共的,所以我无法弄清楚。除非它的 Rectangle::Rectangle(string col, int len, int br):length(len), breadth(br) 然后在构造函数内设置颜色或其他东西。
它只值 3 分,所以如果没有人愿意回答,那也没什么大不了的,但我想如果我要从事程序员的职业,那么了解尽可能多的信息符合我的利益。 ;)
感谢您的帮助。
PS,参见Rectangle
中的getArea()
。当我删除它时,它告诉我“无法实例化抽象类”。这意味着什么?
编辑:这是主要的:
void main (void)
{
Rectangle rect1 ("blue",5,6);
Rectangle *prect2 = new Rectangle("red",5,6);
rect1.setColour("red");
rect1.printDetails();
prect2->printDetails();
}
EDIT: This question came up and I think I aced it! Go StackOverflow!! :D
I have exams coming up, and one of the questions on last year's exams was to spot the problem with implementation of the following constructor and to write a corrected one.
Rectangle::Rectangle(string col, int len, int br)
{
setColour(col);
length =len;
breadth=br;
}
The class definitions are as follows:
class Polygon
{
public:
Polygon(string col="red");
void printDetails(); // prints colour only
virtual double getArea()=0;
void setColour(string col);
private:
string colour;
};
class Rectangle : public Polygon
{
public:
Rectangle(string, int, int);
void printDetails(); // prints colour and area
// for part 3, delete the line below
double getArea();
private:
int length;
int breadth;
};
I've written the code into the compiler and it runs fine. I'm guessing the question is relating to inheritance, since string colour;
is private, but setColour
is public so I cant figure it out. Unless its Rectangle::Rectangle(string col, int len, int br):length(len), breadth(br)
and then set the colour inside the construcor or something.
Its only worth 3 marks so its not that big a deal if nobody wants to answer, but I figure if I'm going to have a career as a programmer, its in my interest to know as much as possible. ;)
Thanks for any help.
PS, see getArea()
in Rectangle
. When I remove that it tells me it "cannot instantiate the abstract class". What does that mean?
EDIT: Here's the main:
void main (void)
{
Rectangle rect1 ("blue",5,6);
Rectangle *prect2 = new Rectangle("red",5,6);
rect1.setColour("red");
rect1.printDetails();
prect2->printDetails();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我没有看到任何错误,尽管您可以通过使用初始化列表来提高效率(否则两个类的私有成员都会初始化两次):
请注意,初始化列表也可以调用 Polygon 的构造函数。
请参阅为什么我应该更喜欢使用成员初始化列表? 有关使用初始化列表优点的完整说明。
I don't see anything wrong, though you could make it more efficient by using an initialization list (otherwise your private members of both classes get initialized twice):
Notice that the initialization list can call the constructor of Polygon as well.
See Why should I prefer to use member initialization list? for a complete description of the advantages of using initialization lists.
如果是关于最佳 C++ 实践,那么:
If it's about best C++ practices, then:
我看到的唯一一件事是有两个 printDetails() 但基类不是虚拟的,因此您不会获得预期的多态行为。
The only thing I see off the bat is there is two printDetails() but the base class one is not virtual so you would not get the polymorphic behavior expected.
我看到的主要“问题”(有点小)是派生构造函数让父类使用其默认的 colo(u)r 值(“红色”),然后提供自己的值。这有点浪费,因为你本可以从一开始就给它正确的。
现在,完成上述操作后,您不妨以这种方式初始化所有成员:
嗯。现在我再看这个,又发现了另外一个问题。您的构造函数通过复制传入
std::string
对象,而不是修改它们。这也太浪费了。所有构造函数string
参数都应更改为string const &
参数。这可能避免在运行时对字符串进行额外的复制构造,并通知编译器和用户您实际上并未修改输入字符串(当您实际上没有修改时,这是一个很好的做法)。因此,最终版本看起来更像是:
对于每个调用的 Rectangle 构造函数,此公式将 4 个 std::string 构造(和 3 个销毁)减少到 2 个。它可以通过对
Polygon
构造函数进行相同的更改,可以进一步简化为 1。The main "issue" I see (and it is kinda minor) is that the derived constructor lets the parent class use its default colo(u)r value ("red"), and then supplies its own. That's kinda wasteful, when you could have given it the correct one from the get-go.
Now, having done the above, you might as well intialize all the members that way:
Hmmm. Now that I look at this, there's another thing wrong with it. Your constructors are passing in
std::string
objects by copy, and not modifying them. That's a waste too. All the constructorstring
parameters ought to be changed tostring const &
parameters. This potentially avoids an extra copy construction of a string at runtime, and notifies the compiler and the users that you aren't actually modifying the input strings (which is good practice when you in fact aren't).So the final version would look more like:
This formulation takes you from 4
std::string
constructions (and 3 destructions) for everyRectangle
constructor called down to 2. It can be further taken down to one by making the same change to thePolygon
constructor.您应该使用 col 参数调用基本构造函数:
关于 getArea():
当您删除它时它无法编译的原因是因为该函数被标记为 纯虚拟 在 Polygon 类中
virtual double getArea()=0;
使用=0
;You should call the base constructor with the col parameter:
Concerning the getArea():
The reason it doesn't compile when you remove it is because that function is marked as pure virtual in your Polygon class
virtual double getArea()=0;
using the=0
;对于您关于 Rectangle::getArea() 的 PS:
virtual double getArea()=0;
在 Polygon 中的声明意味着该函数是一个 纯虚函数。您可以从概念上思考这一点:“所有多边形都有一个面积,所以我应该能够询问它是什么,但除非多边形具有特定类型(正方形、圆形),否则它不会知道它的面积是什么”。这意味着您的 Polygon 类是一个抽象类。通过不在 Rectangle 类中定义 getArea() ,您的矩形类也是一个抽象类。您无法实例化 Rectangle,因为编译器不知道任何
Rectangle::getArea()
函数定义。For your PS regarding
Rectangle::getArea()
: the declaration in Polygon ofvirtual double getArea()=0;
means that the function is a pure virtual function. You can think of this conceptually: "All polygons have an area, so I should be able to ask what it is, but unless the polygon has a particular type (square, circle), it won't know what its area is".What this means is that your Polygon class is an abstract class. By not defining
getArea()
in the Rectangle class, your rectangle class is also an abstract class. You can't instantiate a Rectangle because the compiler doesn't know about anyRectangle::getArea()
function definition.您还可以在初始化列表中添加对基类构造函数的调用:
它使用基类的构造函数,因此更简洁。
You can also add call to the base class constructor in your initializer list:
That uses the base class' constructor, so is a bit neater.
我可以在这里想到一些可能的问题:
使用初始化列表来分配值。
调用基类构造函数来设置颜色。
字符串可能不是表示颜色的最佳类型。也许枚举或单独的颜色类在这里会更好。如果处理得当,这还可以防止传递无效颜色。
谈到无效值:长度和宽度应该在构造函数中进行验证(您不想最终得到负值,是吗?)。至少使用一个断言。它对发布版本没有影响,但可以防止开发错误。对于更公共的界面,例外也可能是一种选择(这在某种程度上是个人喜好)。
如果您确实想使用字符串作为颜色,请通过常量引用传递它(并且可能测试空字符串等边缘情况)。
printDetails
可能应该是虚拟,因此您可以使用基类指针来调用它。当前的实现可能不会按预期运行。该类似乎是为多态性而设计的。如果需要从基类指针中删除,则必须定义虚拟析构函数。由于已经有一个虚拟方法,因此它可能也不会造成伤害。
getArea
和printDetails
应声明为 const,以便可以在 const 对象上调用它们。它们不应修改对象。这只是可能性的列表。其中许多取决于类的预期用途,可能不需要,但仔细考虑它们并没有什么坏处。
I can think of a number of possible problems here:
Use initializer lists to assign the values.
Call the base class constructor to set the color.
A string might not be the best type to represent a color. Maybe an enum or a separate color class would be better here. This also prevents passing invalid colors, if properly done.
Speaking of invalid values: length and breadth should be validated in the constructor (you don't want to end up with negative areas, do you?). At least use an assertion. It has no effect on release builds, but prevents development errors. For a more public interface, exceptions may also be an option (this is personal taste to some degree).
If you really want to use a string for the color, pass it by const reference (and probably test for edge cases like the empty string).
printDetails
should probably be virtual, so you can call it with a base class pointer. The current implementation might not behave as intended.The class seems to be designed for polymorphism. A virtual destructor has to be defined, if deletion from a base class pointer is required. Since there already is a virtual method, it probably won't hurt either.
getArea
andprintDetails
should be declared const, so that they can be called on const objects. They shouldn't modify the object.This is just a list of possibilities. Many of them depend on the intended usage of the class and might not be needed, but it doesn't hurt to consider them carefully.
如前所述,printDetails 不会按预期运行。
我还认为,仅在 Rectangle 类中声明 getArea() 有点作弊,因为您没有提供它的实现,如果您碰巧在代码中调用它,您会收到链接器错误。
As mentioned printDetails won't behave as expected.
I also think that just declaring getArea() within Rectangle class is kinda cheating because you do not provide implementation for it, and if you happen to call it within you code you would get a linker error.
可能存在初始化顺序问题。 Polygon::setColour可以调用纯虚拟的Polygon::getArea。 (没有迹象表明需要这样做,但存在这种可能性。)矩形中的实现可能需要长度和宽度来计算面积,但它们不是尚未初始化。
最小的修复方法是在调用 setColour 之前初始化长度和宽度:
当然,最好放弃
纯虚拟getArea()
来自 Polygon 的声明,因为任何 Polygon 方法似乎都不需要它。但这超出了问题的范围。An initialization order issue is possible. Polygon::setColour could call the pure virtual Polygon::getArea. (There is no indication that it would need to, but the possibility exists.) The implementation in Rectangle would presumably need length and breadth to compute the area, but they are not initialized yet.
The minimal fix is to initialize length and breadth before calling setColour:
It would be best, of course, to drop the
pure virtual getArea()
declaration from Polygon because it doesn't appear to be needed by any Polygon methods. But that is outside of the scope of the question.