问题与C + +构造函数

编辑:这个问题出来了,我认为我aced它! 去StackOverflow! :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; }; 

我已经将代码写入编译器,运行良好。 我猜这个问题是关于inheritance,因为string colour; 是私人的,但setColour是公开的,所以我不能弄明白。 除非它的Rectangle::Rectangle(string col, int len, int br):length(len), breadth(br)然后在construcor里面设置颜色或者其他东西。

它的唯一价值就是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(); } 

我没有看到任何错误,虽然你可以通过使用初始化列表(否则你的两个类的私有成员初始化两次)更有效率:

 Rectangle::Rectangle(string col, int len, int br) : Polygon(col), length(len), breadth(br) { } 

请注意,初始化列表也可以调用Polygon的构造函数。

请参阅我为什么更喜欢使用成员初始化列表? 有关使用初始化列表的优点的完整说明。

如果是关于最佳的C ++实践,那么:

  1. 通过const引用传递string参数;
  2. 使用初始化器列表并通过将其传递给父构造函数来初始化颜色,而不是setColour。

我唯一看不到的是有两个printDetails(),但是基类不是虚拟的,所以你不会得到预期的多态行为。

我看到的主要“问题”(它有点小)是派生的构造函数让父类使用其默认的colo(u)r值(“红色”),然后提供自己的。 这是有点浪费的,当你可以从一开始就给它正确的。

 Rectangle::Rectangle(string col, int len, int br) : Polygon(col) { length =len; breadth=br; }; 

现在,做完以上这些,你可以像所有的成员一样:

 Rectangle::Rectangle(string col, int len, int br) : Polygon(col), length(len), breadth(br) {}; 

嗯。 现在我看到这个,还有一个错误的地方。 你的构造函数通过拷贝传递std::string对象,而不是修改它们。 这也是一种浪费。 所有的构造函数string参数都应该更改为string const &参数。 这可能会避免在运行时对string进行额外的拷贝构造,并通知编译器和用户您实际上并没有修改inputstring(当您实际上不是这样做的时候,这是很好的做法)。

所以最终版本看起来更像是:

 Rectangle::Rectangle(string const & col, int len, int br) : Polygon(col), length(len), breadth(br) {}; 

这个公式从每个Rectangle构造函数的4个std::string结构(和3个破坏)中调用到2个。通过对Polygon构造函数进行相同的修改,可以进一步减less为1。

您应该使用col参数调用基础构造函数:

 Rectangle::Rectangle(string col, int len, int br) : Polygon(col) { //setColour(col); length =len; breadth=br; } 

关于getArea()
删除它时不编译的原因是因为该函数在Polygon类中被标记为纯虚函数virtual double getArea()=0; 使用=0 ;

对于你的关于Rectangle::getArea() PS: virtual double getArea()=0; 意味着该函数是一个纯虚函数 。 你可以从概念上思考这个问题:“所有的多边形都有一个区域,所以我可以问它是什么,除非多边形具有特定的types(正方形,圆形),否则它将不知道它的面积是多less”。

这意味着你的Polygon类是一个抽象类。 通过不在Rectangle类中定义getArea() ,你的矩形类也是一个抽象类。 你不能实例化一个Rectangle,因为编译器不知道任何Rectangle::getArea()函数的定义。

您还可以在初始化程序列表中添加对基类构造函数的调用:

 Rectangle::Rectangle(string col, int len, int br) : Polygon(col), length(len), breadth(br) 

这使用基类的构造函数,所以有点整洁。

我可以在这里想到一些可能的问题:

  1. 使用初始值设定项列表来分配值。

  2. 调用基类的构造函数来设置颜色。

  3. string可能不是表示颜色的最佳types。 也许一个枚举或一个单独的颜色类将在这里更好。 这也可以防止通过无效的颜色,如果做得好。

  4. 说到无效值 :长度和宽度应该在构造函数中进行validation(你不想结束负面区域,是吗?)。 至less使用一个断言 。 它对发布版本没有影响,但可以防止发展错误。 对于一个更公共的界面来说, 例外也可能是一种select(这在某种程度上是个人的品味)。

  5. 如果你真的想使用一个string的颜色,传递它的const引用 (并可能testing边缘的情况下,如空string)。

  6. printDetails应该是虚拟的 ,所以你可以用一个基类指针来调用它。 目前的实施可能不像预期的那样。

  7. 这个类似乎是为多态而devise的。 如果需要从基类指针中删除,则必须定义虚拟析构函数 。 既然已经有一个虚拟的方法,它可能也不会伤害。

  8. getAreaprintDetails应该声明为const ,以便可以在const对象上调用它们。 他们不应该修改对象。

这只是一个可能性列表。 它们中的许多取决于class级的预期用途,可能并不需要,但仔细考虑它们并没有什么坏处。

正如所提到的printDetails不会按预期行事。
我也认为只是在Rectangle类中声明getArea()是有点作弊的,因为你不提供它的实现,如果你碰巧在你的代码中调用它,你会得到一个链接器错误。

初始化顺序问题是可能的。 Polygon :: setColour可以调用纯虚拟Polygon :: getArea 。 (没有迹象表明它需要,但存在的可能性。)Rectangle中的实现大概需要长度宽度来计算面积,但是它们还没有被初始化。

最小的修正是在调用setColour之前初始化长度宽度

 Rectangle::Rectangle(string col, int len, int br) { length =len; breadth=br; setColour(col); } 

当然,最好的做法是从Polygon中删除pure virtual getArea()声明,因为它似乎不是任何Polygon方法所需要的。 但这不在问题的范围之内。