Issue with C++ constructor - c++

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();
}

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):
Rectangle::Rectangle(string col, int len, int br)
: Polygon(col), length(len), breadth(br)
{
}
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.

If it's about best C++ practices, then:
Pass string parameters by const reference;
Use initializer list and initialize colour by passing it to parent constructor, not setColour.

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.

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.
Rectangle::Rectangle(string col, int len, int br) : Polygon(col) {
length =len;
breadth=br;
};
Now, having done the above, you might as well intialize all the members that way:
Rectangle::Rectangle(string col, int len, int br)
: Polygon(col), length(len), breadth(br) {};
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 constructor string parameters ought to be changed to string 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:
Rectangle::Rectangle(string const & col, int len, int br)
: Polygon(col), length(len), breadth(br) {};
This formulation takes you from 4 std::string constructions (and 3 destructions) for every Rectangle constructor called down to 2. It can be further taken down to one by making the same change to the Polygon constructor.

You should call the base constructor with the col parameter:
Rectangle::Rectangle(string col, int len, int br) : Polygon(col)
{
//setColour(col);
length =len;
breadth=br;
}
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;

For your PS regarding Rectangle::getArea(): the declaration in Polygon of virtual 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 any Rectangle::getArea() function definition.

You can also add call to the base class constructor in your initializer list:
Rectangle::Rectangle(string col, int len, int br)
: Polygon(col), length(len), breadth(br)
That uses the base class' constructor, so is a bit neater.

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 and printDetails 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.

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.

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:
Rectangle::Rectangle(string col, int len, int br)
{
length =len;
breadth=br;
setColour(col);
}
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.

Related

How do I use a class variable inside of that class? (C++)

This is the code I'm trying to run:
class poly {
public:
int vnum;
vrtx vrts[this->vnum];
};
(Note: The class name "poly" and other class "vrtx" are named as such to approximate the purpose of the problematic snippet. Vrtx is a class with int x, y, z;)
At first, the code didn't contain the "this->" pointer at all. I was confused why it wasn't working, and then realized that "vnum" doesn't mean anything. I needed an object.poly.vnum sort of thing so that I'm referencing a specific value. I tried "this.," "this.poly.," and the displayed "this->," but none of them work. I'm not great with pointers, so any advice would be appreciated!
I've looked at similar questions, but none of them address this issue in such a way that I could make the necessary fix with the information provided.
Here's a code fragment that should help.
class Poly
{
public:
int vnum;
std::vector<vrtx> vrts;
Poly(int capacity)
: vnum(capacity)
{ vrts.resize(vnum);}
};
The above fragment uses std::vector since the std::vector can expand dynamically (at run-time). The constructor uses the resize method to expand the std::vector to the given capacity.
Arrays are a pain to resize during run-time, so use std::vector.

Why is this giving me the invalid base class error?

I have two classes called Renderable and Triangle. The latter is supposed to be deriving from the former. I plan to be passing an array and its length into the Triangle constructor, which in turn will pass it to the constructor in the Renderable class that will handle the corresponding parameters. Here are the header files:
Renderable.h
class Renderable {
protected:
const int dataLength = 0;
const float* data[0] ;
public:
Renderable();
Renderable(int dataLength, float* data[]);
virtual void render() const =0 ;
};
Triangle.h
#pragma once
#include <glad/glad.h>
#include "Renderable.h"
class Triangle : public Renderable {
public:
void render() const;
};
So the problem is that the error check gave me invalid base class. I did some research and saw something about arrays' not being able to be an instance variable without specified size but this is still quite confusing to me. Could someone please enlighten me on this?
Also is there a more efficient solution to problems like this?
Thank you!
const float* data[0] ;
This array member declaration is ill-formed. The size of an array variable may not be 0.
Otherwise the example is well-formed (assuming the functions are defined in some translation unit).
Also is there a more efficient solution to problems like this?
Solution is to not declare an array variable of size 0.
So the problem here is that the code design that I was going for is undesirable and I should either use std::vector or making another subtype of the Renderable class with a fixed array length and then extend from it.

Comparing data between two objects of a class

So, I've created a class and then construct two separate instances of that class:
disc discOne; // Construct objects
disc discTwo;
The declaration of the class is done separately through a header file:
class disc
{
public:
disc();
~disc();
void changeRadius(short);
void throwDisc(short, short);
void printLocation() const;
void printInfo() const;
private:
short radius;
short xlocation;
short ylocation;
};
I can use the printInfo() and changeRadius() functions for example, but how can I compare (for example) the radius between these two objects? I want to do something more complex than this, but if I understand the basics I want to try and figure it out.
The problem I'm running in to is that I've used structures in the past, which (if this was the case), I would simply go:
discOne.radius > discTwo.radius
Or something similar. But, that syntax for classes calls a function tied to that class. Sorry for the rambling, but I'm having trouble articulating it - probably why I've struggled to find any guidance through my own searches on the internet.
Three ways:
Use a getter method getRadius() const {return radius;}
and just compare as you always did.
Use overload for operator< and operator> if you want to compare two objects directly (but this doesn't seems the right case.
Declare a friend function bool compareRadius(const Disc& discOne, const Disc& discTwo) to perform the comparison without involving directly the objects.
Of course the simpliest way is the first. I just showed some other option you could consider for similar problems.
Edit: Answer #3 is based on Scott Meyer's Effective C++, item 23 (though it specifies non-friend).
You could add a "getter" to your class (like short getRadius() const) through which you can obtain a value to compare: discOne.getRadius() < discTwo.getRadius().
Alternatively you could add a operator< overload to disc itself, and have it perform the comparison between radii. However, this only makes sense if the radius is the only property of the disc (which it isn't — you have location also), and if comparing radii is equivalent to comparing discs (and I'm not convinced that this would be logical).
Beyond that there are all sorts of clumsy solutions, like adding a bool radiusIsLesserThatThisOtherDiscsRadius(const disc& otherDisc) const member function.
But, that syntax for classes calls a function tied to that class
Actually, that's not true; C++ does not have "structures", so struct introduces a class too, and discOne.radius > discTwo.radius would have worked just fine here if radius were not a private data member. But it being a private data member is appropriate.
struct disc
{
public:
disc();
~disc();
void changeRadius(short);
void throwDisc(short, short);
void printLocation() const;
void printInfo() const;
private:
short radius;
short xlocation;
short ylocation;
};
// ^ Exactly the same thing; your approach still won't work, for the same reason
Simple solution to overload the > operator on objects like below to compare radius of two objects of the class.
discOne > discTwo;
you can overload > according to your requirement, Here is the simple one
bool disc :: operator > (disc my_disc)
{
if(radius > my_disc.radius)
return true;
else
return false;
}
Above one is one of the solution to solve your problem. There are other ways by which you can compare two objects as suggested by others. Use separate member function( or friend function) to do the same task.

Should class Square publicly inherit from class Rectangle?

I find this question very interesting after reading the part of "Effective C++" about public inheritance. Before it would be common sense for me to say yes, because every square is a rectangle, but not necessarily other way around. However consider this code:
void makeBigger(Rectangle& r) {
r.setWidth(r.width() + 10);
}
This code is perfectly fine for a Rectangle, but would break the Square object if we passed it to makeBigger - its sides would become unequal.
So how can I deal with this? The book didn't provide an answer (yet?), but I'm thinking of a couple of ways of fixing this:
Override setWidth() and setHeight() methods in Square class to also adjust the other side.
Drawback: code duplication, unnecessary 2 members of Square.
For Square not to inherit from Rectangle and be on its own - have size, setSize() etc.
Drawback: weird - squares are rectangles after all - it would be nice to reuse Rectangle's features such as right angles etc.
Make Rectangle abstract (by giving it a pure virtual destructor and defining it) and have a third class that represents rectangles that are not squares and inherits from Rectangle. That will force us to change the above function's signature to this:
void makeBigger(NotSquare& r);
Can't see any drawbacks except having an extra class.
Is there a better way? I'm leaning towards the third option.
This is one of the key principles in OO design that I find gets handled incorrectly. Mr Meyer does an excellent job of of discussing it the book you are referring to.
The trick is to remember that the principles must be applied to concrete use cases. When using inheritence, remember that the key is that the "is a" relationship applies to an object when you want to use that object as a ... So whether a square is a rectangle or not depends on what you are going to be doing with rectangles in the future.
If you will be setting width and height of a rectangle independently, then no, a square is not a rectangle (in the context of your software) although it is mathematically. Thus you have to consider what you will be doing with your base objects.
In the concrete example you mention, there is a canonical answer. If you make makeBigger a virtual member function of rectangle, then each one can be scaled in a way that is appropriate to a class. But this is only good OO design if all the (public) methods which apply to a rectangle will apply to a square.
So let's see how this applies to your efforts so far:
I see this kind of thing in production code pretty often. It's excusable as a kludge to fix a gap in an otherwise good design, but it is not desirable. But it's a problem because it leads to code which is syntactically correct, but semantically incorrect. It will compile, and do something, but the meaning is incorrect. Lets say you are iterating over a vector of rectangles, and you scale the width by 2, and the height by 3. This is semantically meaningless for a square. Thus it violates the precept "prefer compile time errors to runtime errors".
Here you are thinking of using inheritance in order to re-use code. There's a saying "use inheritance to be re-used, not to re-use". What this means is, you want to use inheritance to make sure the oo code can be re-used elsewhere, as its base object, without any manual rtti. Remember that there other mechanisms for code re-use: in C++ these include functional programming and composition.
If square's and rectangles have shared code (e.g. computing the area based on the fact that they have right angles), you can do this by composition (each contains a common class). In this trivial example you are probably better off with a function though, for example:
compute_area_for_rectangle(Shape* s){return s.GetHeight() * s.GetWidth());}
provided at a namespace level.
So if both Square and Rectangle inherit from a base class Shape, Shape having the following public methods: draw(), scale(), getArea() ..., all of these would be semantically meaningful for whatever shape, and common formulas could be shared via namespace level functions.
I think if you meditate on this point a little, you'll find a number of flaws with your third suggestion.
Regarding the oo design perspective: as icbytes mentioned, if you're going to have a third class, it makes more sense that this class be a common base that meaningfully expresses the common uses. Shape is ok. If the main purpose is to draw the objects than Drawable might be another good idea.
There are a couple other flaws in the way you expressed the idea, which may indicate a misunderstanding on your part of virtual destructors, and what it means to be abstract. Whenever you make a method of a class virtual so that another class may override it, you should declare the destructor virtual as well (S.M. does discuss this in Effective C++, so I guess you would find this out on your own). This does not make it abstract. It becomes abstract when you declare at least one of the methods purely virtual -- i.e. having no implementation
virtual void foo() = 0; // for example
This means that the class in question cannot be instantiated. Obviously since it has at least one virtual method, it should also have the destructor declared virtual.
I hope that helps. Keep in mind that inheritence is only one method by which code can be re-used. Good design comes out of the optimal combination of all methods.
For further reading I highly recommend Sutter and Alexandrescu's "C++ Coding Standards", especially the section on Class Design and Inheritence. Items 34 "Prefer composition to inheritence" and 37 "Public inheritence is substitutability. Inherit, not to reuse, but to be reused.
It turns out the easier solution is
Rectangle makeBigger(Rectangle r)
{
r.setWidth(r.width() + 10);
return r;
}
Works perfectly well on squares, and correctly returns a rectangle even in that case.
[edit]
The comments point out that the real problem is the underlying call to setWidth. That can be fixed in the same way:
Rectangle Rectangle::setWidth(int newWidth) const
{
Rectangle r(*this);
r.m_width = newWidth;
return r;
}
Again, changing the width of a square gives you a rectangle. And as the const shows, it gives you a new Rectangle without changing the existing Rectangle The previous function now becomes even easier:
Rectangle makeBigger(Rectangle const& r)
{
return r.setWidth(r.width() + 10);
}
Except from having an extra class there are no serious drawbacks of your 3rd solution (called also Factor out modifiers). The only I can think of are:
Suppose I have a derived Rectangle class with one edge being a half of the other, called for example HalfSquare. Then according to your 3rd solution I'd have to define one more class, called NotHalfSaquare.
If you have to introduce on more class then let it be rather Shape class both Rectangle, Square and HalfSquare derive from
If you want your Square to be a Rectangle, it should publicly inherit from it. However, this implies that any public methods that work with a Rectangle must be appropriately specialised for a Square. In this context
void makeBigger(Rectangle& r)
should not be a standalone function but a virtual member of Rectangle which in Square is overridden (by providing its own) or hidden (by using makeBigger in the private section).
Regarding the issue that some things you can to do a Rectangle cannot be done to a Square. This is a general design dilemma and C++ is not about design. If somebody has a reference (or pointer) to a Rectangle that actually is a Square and want to do an operation that makes no sense for a Square, then you must deal with that. There are several options:
1 use public inheritance and make Square throw an exception if an operation is attempted that is not possible for a Square
struct Rectangle {
double width,height;
virtual void re_scale(double factor)
{ width*=factor; height*=factor; }
virtual void change_width(double new_width) // makes no sense for a square
{ width=new_width; }
virtual void change_height(double new_height) // makes no sense for a square
{ height=new_height; }
};
struct Square : Rectangle {
double side;
void re_scale(double factor)
{ side *= factor; } // fine
void change_width(double)
{ throw std::logic_error("cannot change width for Sqaure"); }
virtual void change_height(double)
{ throw std::logic_error("cannot change height for Sqaure"); }
};
This really is awkward and not appropriate if change_width() or change_height() are integral parts of the interface. In such a case, consider the following.
2 you can have one class Rectangle (which may happen to be square) and, optionally, a separate class Square that can be converted (static_cast<Rectangle>(square)) to a Rectangle and hence act as a Rectangle, but not be modified like a Rectangle
struct Rectangle {
double width,height;
bool is_square() const
{ return width==height; }
Rectangle(double w, double h) : width(w), height(h) {}
};
// if you still want a separate class, you can have it but it's not a Rectangle
// though it can be made convertible to one
struct Square {
double size;
Square(Rectangle r) : size(r.width) // you may not want this throwing constructor
{ assert(r.is_square()); }
operator Rectangle() const // conversion to Rectangle
{ return Rectangle(size,size); }
};
This option is the correct choice if you allow for changes to the Rectangle that can turn it into a Square. In other words, if your Square is not a Rectangle, as implemented in your code (with independently modifiable width and height). However, since Square can be statically cast to a Rectangle, any function taking an Rectangle argument can also be called with a Square.
You say: "because every square is a rectangle" and here the problem lies exactly. Paraphrase of famous Bob Martin's quote:
The relationships between objects are not shared by their
representatives.
(original explanation here: http://blog.bignerdranch.com/1674-what-is-the-liskov-substitution-principle/)
So surely every square is a rectangle, but this doesn't mean that a class/object representing a square "is a" class/object representing a rectangle.
The most common real-world, less abstract and intuitive example is: if two lawyers struggle in the court representing a husband and a wife in the context of a divorce, then despite the lawyers are representing the people during a divorce and being currently married they are not married themselves and are not during a divorce.
My idea:
You have a superclass, called Shape. Square inherits from Shape. It has the method resize(int size ). A Rectangle is ClassRectangle, inheriting from Shape but implementing interface IRecangle. IRectangle has method resize_rect(int sizex, int size y ).
In C++ interfaces are created by the usage of so called pure virtual methods. It is not fully well implemented like in c# but for me this is even better solution than third option. Any opinions ?

Where to place in game object definitions?

This may sound like a stupid question, but I'm not sure how else to do this.
In my c++ ASCII-based roguelike, I will have lots and lots of Objects. Each allocated, in-game, object will have some properties in common. (Name, Size, ObjectID, Appearance, Etc.) Normally, I would use static variables for this, but that would require creating a new class and initializer for each and every Object. Instead, I've decided have each allocated object contain a pointer to a given ObjectDef, which I can then use to get around this. I will create a new class for a given type of object, when the object has new functionality that needs to be implemented.
That said, where do I define all of these object definitions? I'd like to have them in arrays, but I know global variables are bad, bad, bad.
Some general tips would be great. Thanks.
class WorldObjectDef //WHAT WE HAVE A LIST OF
{
protected:
std::string m_name;
float m_size;
int m_type;
int m_id;
AsciiNode m_node;
public:
WorldObjectDef(std::string, float, int, int, const AsciiNode &);
int getId() const;
std::string getName() const;
float getSize() const;
AsciiNode getNode() const;
};
class WorldObject //WHAT'S ALLOCATED IN A LEVEL
{
WorldObjectDef * m_def;
public:
WorldObject(const WorldObjectDef &);
int getId() const;
std::string getName() const;
float getSize() const;
AsciiNode getNode() const;
};
Something I've been wondering: Is there anything wrong with html-like code tags? God it's annoying to space indent every line.
I often create List<> that holds all the active objects ( ie. objects that are ingame and in use), that can be used to manipulate all the data in one loop.
That list could be defined anywhere, where its visibility is high enought. If it needs to be global, then so be it. Better to get the code working, than think if its running at max fps.
Dont use globals and gotos are the first warnings i remember to read about. Im not saying you should ignore those warnings, but to understand why its not good practice to use em in large scale.
Globals are bad, becouse they stay live until program exist, or manually disposed. If you have main loop, witch i think you have, you should define those variables in it.
I really think there's a problem here.
You don't necessarily need a new class definition for each object type in your game world (Chair, Table, Pencil); but you should have a class definition for each category of object based on the type of behavior that object can have.
For example, a Cat versus a Chair. A cat can probably move around under it's own power, make noises, etc. A chair on the other hand might be moved by a player, sat in, or even turned into firewood or whatever.
So, you'd have a top level class definition for WorldObject of which you would derive an Animal class and maybe an InanimateClass. The Animal class might have a type enumeration for Dog, Cat or Zebra. While the InanimateClass might be further subdivided depending on actions that characters may take with them.
All of these objects would be stored in a List and you could test the object types to determine what operations you can take on them.
This way you can keep the attributes of the objects with the object instances themselves and save yourself a LOT of work.