问题与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 ++实践,那么:
- 通过const引用传递string参数;
- 使用初始化器列表并通过将其传递给父构造函数来初始化颜色,而不是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)
这使用基类的构造函数,所以有点整洁。
我可以在这里想到一些可能的问题:
-
使用初始值设定项列表来分配值。
-
调用基类的构造函数来设置颜色。
-
string可能不是表示颜色的最佳types。 也许一个枚举或一个单独的颜色类将在这里更好。 这也可以防止通过无效的颜色,如果做得好。
-
说到无效值 :长度和宽度应该在构造函数中进行validation(你不想结束负面区域,是吗?)。 至less使用一个断言 。 它对发布版本没有影响,但可以防止发展错误。 对于一个更公共的界面来说, 例外也可能是一种select(这在某种程度上是个人的品味)。
-
如果你真的想使用一个string的颜色,传递它的const引用 (并可能testing边缘的情况下,如空string)。
-
printDetails
应该是虚拟的 ,所以你可以用一个基类指针来调用它。 目前的实施可能不像预期的那样。 -
这个类似乎是为多态而devise的。 如果需要从基类指针中删除,则必须定义虚拟析构函数 。 既然已经有一个虚拟的方法,它可能也不会伤害。
-
getArea
和printDetails
应该声明为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方法所需要的。 但这不在问题的范围之内。