Is the Wikipedia example at this article about method overiding in C++ correct?
Please see the code below where I have mentioned a comment //INCORRECT
Slightly confused about overiding in C++ and run time polymorphism. What should this cast do?
#include <iostream>
class Rectangle {
public:
explicit Rectangle(double l, double w) : length(l), width(w) {}
virtual void print() const;
private:
double length;
double width;
};
void Rectangle::print() const { // print() method of base class
std::cout << "Length = " << this->length << "; Width = " << this->width;
}
class Box : public Rectangle {
public:
explicit Box(double l, double w, double h) : Rectangle(l, w), height(h) {}
virtual void print() const; // virtual is optional here, but it is a good practice to remind it to the developer
private:
double height;
};
void Box::print() const { // print() method of derived class
Rectangle::print(); // Invoke parent print() method.
std::cout << "; Height= " << this->height;
}
int main(int argc, char** argv) {
Rectangle rectangle(5.0, 3.0); rectangle.print();
// outputs:
// Length = 5.0; Width = 3.0
Box box(6.0, 5.0, 4.0);
// the pointer to the most overridden method in the vtable in on Box::print
//box.print(); // but this call does not illustrate overriding
static_cast<Rectangle&>(box).print(); // this one does
// outputs:
// Length = 5.0; Width = 3.0; Height= 4 // INCORRECT
//But it actually outputs Length = 6; Width = 5; Height = 4
getchar();
return 0;
}
You're right - the output mentioned is incorrect.
The cast simply demonstrates that a box is a kind of rectangle (inheriting from it) and that even as a rectangle, the method override will still be effective and the Box version of the print method will be called.
Feel free to fix the comment in Wikipedia: the output should indeed be Length = 6; Width = 5; Height = 4.
The other part is correct, though: the code where a Box.print() is called even after the Box reference has been statically cast to a reference to its superclass is indeed a demonstration of how overriding of a virtual method works in C++.
Another way to demonstrate the same point is through use of a pointer instead of a reference:
Rectangle *boxPtr = &box;
boxPtr->print();
this line: static_cast<Rectangle&>(box).print(); has same effect as this code would have:
Rectangle & r = box;
r.print();
and also same effect as this code would have:
Rectangle * r = &box;
r->print();
It means that Box object was created (Box box(6.0, 5.0, 4.0); = in runtime you see Box) and it doesn't matter what is the type of pointer / reference where you store this object. The fact that you store box as a Rectangle* is what you see in compile time.
Most important fact about overriding virtual methods is that about "which method will be called?" is decided in runtime.
Hope this helps.
The comment in the article was indeed wrong (and has now been fixed); it should have printed 6,5, and 4 as you say.
The point of the cast is to demonstrate that, even if you call the virtual function via a reference to the base class (Rectangle), it will call the override associated with the actual type of the object (Box) - you still get the three values printed by Box::print(), rather than the two printed by Rectangle::print().
Related
I'm learning C++.
Came across data encapsulation and data hiding at a website, check out the following piece of code:
#include<iostream.h>
#include<conio.h>
class sum {
private: int a, b, c;
public:
void add() {
clrscr();
cout << "Enter any two numbers: ";
cin >> a >> b;
c = a + b;
cout << "Sum: " << c;
}
};
void main() {
sum s;
s.add();
getch();
}
NOW. As it says here that:
The main advantage of using of encapsulation is to secure the data from other methods, when we make a data private then these data only use within the class, but these data not accessible outside the class.
What happens underneath the code, what does the compiler do that makes it inaccessible to other classes? And in the given example what was the reason behind defining a,b and c as private.
What were they trying to achieve by hiding "just the declarations of the three variables"? Because anyone can see that inside public three numbers being used are a,b, and c - first two for input and third one for output.
How is this possible that the data under private can't be accessed
outside the class?
Compiler makes sure you don't. If you try to access say a outside class, your code will not compile.
And in the given example what was the reason behind defining a,b and c
as private.
It could be anything! But as a result, a,b and c are not accessible outside members of class.
Basically you want to hide some variables in your class for the sake of consistency. So that you or your clients can not produce a code that makes unwanted and uncontrolled changes.
Updates:
What happens underneath the code, what does the compiler do that makes
it unaccessible to other classes?
Compiler implementation check for access level while producing code. If there is something wrong, you will get a syntax error and no machine code will be generated from your file.
And in the given example what was the reason behind defining a,b and c
as private; what were they trying to achieve by hiding "just the
declarations of the three variables"? Because anyone can see that
inside public three numbers being used are a,b, and c - first two for
input and third one for output.
You don't hide variables in your class to make them invisible to others. Private variables that are not intended to be used from outside of the class can be marked as private to limit the potential for coding errors.
As an example consider following class:
class rectangle {
public:
int width;
int height;
int area;
};
void something_important(const rectangle& r) {
// ...
}
What happens if I pass a rectangle of width -10, height 0 and area of -15? There could be a plane crash or a nuclear weapon launched to some wrong target... So I will make sure my rectangles are always valid:
class rectangle {
public:
void set_width(int w) {
if(w) width = w;
else width = 0;
area = width*height;
}
int get_width() const {return width;}
void set_height(int h) {
if(w) height = h;
else height = 0;
area = width*height;
}
int get_height() const {return height;}
int get_area() const {return area;}
private:
int width;
int height;
int area;
};
So no one can make a rectangle of negative height or width, and no one can make a rectangle having a wrong area. (you can not actually change area directly)
I hope it makes sense for you now.
What happens underneath the code, what does the compiler do that makes it unaccessible to other classes?
Not much. The compiler doesn't protect against access to the data. It protects against access to the name of the data. For instance:
void foo(class bar&, int&);
class bar {
int i = 0;
public:
void baz() {
foo(*this, i);
}
};
void foo(class bar& b, int& i) {
//b.i = 42; // This is an error. b.i is private
i = 42; // This is okay, no matter what the local i refers to
}
In the example above, foo() cannot access b.i by name, because it's a private data member. But it can still modify it if it obtains a reference by other means. The member function baz() which has access to that name, binds it to the reference that foo() accepts. Thus allowing for its modification from outside the class's scope.
I was playing around with pointer to the base class, and I casted a rectangle pointer into a circle pointer and called the printradius() function from the rectangle! Could someone explain why this is allowed? Thanks.
#include <iostream>
#include <string>
using namespace std;
class Shape {
};
class Circle: public Shape {
private:
double radius;
public:
Circle(double r)
{ radius = r;}
void printradius()
{ cout << "circle's radius is " << radius << endl;}
};
class Rectangle: public Shape {
private:
double width, length;
public:
Rectangle(double l, double w)
{ length = l; width = w;}
};
int main() {
Rectangle r( 2.0, 2.0); // only a rectangle is created
Shape* s = &r; // up cast into a shape
Circle* c = static_cast<Circle*>(s); //down cast into a circle
c->printradius();
}
output:
circle's radius is 2
What do you mean by "allowed"?
The language explicitly states that the result of such static_cast is undefined, so it is not really "allowed" in this case. In order to perform a valid downcast from Shape * to Circle *, you have to ensure that Shape * actually points to Circle or something derived from Circle. Otherwise, the behavior is undefined.
As for why the compiler did not catch it... The compiler cannot possibly catch errors that depend on run-time conditions. In general case the compiler does not know what your s pointer actually points to.
As for why the language even offers such feature... It offers it because it can be extremely useful when one uses it properly.
The static cast is "because I said so.", in other words, trust me, the programmer, that the thing is what I say it is, a circle pointer in this case. When calling the printradius() method, The this pointer is for r, and when printradius() happens to deref looking for a radius, it finds that first double, with a value of 2.0. There is no crash, or reported error from running this way, but as you know, it makes no sense.
Use a dynamic cast and check the value returned. You will see null, because rectangle and circle are not the same.
I have two classes, in the example added Rectangle and Rectangles. The goal is to make one Rectangles object which holds references to multiple Rectangle objects.
If I change r by r.set_values(4,4) then off coarse r.area() is changed. However if I call rectangles.rects[0].area() it remains 12, and therefore is not changed.
As I understood I am making a reference of r in rectangles, however this seems to be wrong.
How to achieve this?
The code is available here
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
Rectangle* rects;
int nRects;
};
Rectangles::Rectangles(int n) {
rects = new Rectangle[n];
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = *r;
nRects++;
}
int main() {
Rectangle r;
Rectangles rectangles(5);
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() before change:"<<rectangles.rects[0].area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() after change:"<<rectangles.rects[0].area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0].area() before change:12
r.area() after change:16
rectangles.rects[0].area() after change:12
What is wrong with your code is your definition of Rectangles. It stores a pointer (or an array) to a Rectangle. What you want here is not an array of Rectangle's, but an array of references to Rectangle's. Here, the references shall be pointers, so you need to change this accordingly :
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
// Rectangle* rects;
// What you really want :
Rectangle** rects;
int nRects;
};
But then you also need to change the implementation :
Rectangles::Rectangles(int n) {
rects = new Rectangle*[n]; // Array of pointers
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = r; // r is a pointer : just store it, no dereferencing
nRects++;
}
However, this is a bad design : you should not have to use any of these : pointer to pointer (or 'raw array' of pointers), new, and a class whose only purpose is to store an array of things. This is because you already have better tools for this : smart pointers (although you do not need them here either), arrays and dynamic arrays (or vectors).
So, if I were you, this is how I would rewrite your code :
#include <iostream>
#include <vector>
class Rectangle {
public:
void setSize(int w, int h);
int area();
private:
int width, height;
};
void Rectangle::setSize(int w, int h) {
width = w;
height = h;
}
int Rectangle::area() {
return width * height;
}
int main() {
Rectangle r;
std::vector<Rectangle*> rectangles;
r.setSize(4, 3);
rectangles.push_back(&r);
std::cout << "r.area() before change : " << r.area() << std::endl
<< "rectangles[0]->area() before change : "
<< rectangles[0]->area() << std::endl;
r.setSize(4, 4);
std::cout << "r.area() after change : " << r.area() << std::endl
<< "rectangles.rects[0]->area() after change : "
<< rectangles[0]->area() << std::endl;
return 0;
}
Edit :
You might wonder why I used a raw pointer instead of a smart pointer (since I told you to avoid pointers to pointer). This is quite simple : no smart pointer would fit the matter. Let us see why.
std::unique_ptr keeps sole ownership of the object. What if you want another reference to it ? Also, if you ever destroy this smart pointer via std::vector's erase, it would also destroy your object. So if you access it afterwards, you would get some dirty error.
std::shared_ptr keeps shared ownership of the object. Sure, you can have another reference to your object, but the same thing happens if you destroy the pointer. Also, it has some overhead, and is not so easy to use correctly.
std::weak_ptr works with std::shared_ptr, nothing more to say.
A raw pointer, on the contrary, only needs you to ensure that the lifetime of the object is longer or equal to its own lifetime, so that you can always access your object via the pointer. And that is all.
Finally, here is a general rule of thumbs (that I use) :
unique_ptrs are for sole ownership
raw pointers mean whoever gave me the raw pointer guarantees the lifetime of that object to match or exceed my lifetime.
shared_ptrs are for shared ownership
weak_ptrs are for when a system wants to check if the object still exists before using it. This is rare in my code since I find it cleaner to have a system guarantee the lifetime of anything it passes it's subsystems (in which case I use a raw pointer)
class Rectangles {
public:
void addRectangle(Rectangle* r);
vector<Rectangle *> rects;
};
void Rectangles::addRectangle(Rectangle* r) {
rects.push_back(r);
}
int main() {
Rectangle r;
Rectangles rectangles;
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() before change:"<<rectangles.rects[0]->area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() after change:"<<rectangles.rects[0]->area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0]->area() before change:12
r.area() after change:16
rectangles.rects[0]->area() after change:16
I have the following parent child simple classes:
class BoundBases{
public:
virtual ~BoundBases() { }
};
// Rectangular Bounds for tree
class RectBounds : public BoundBases{
public:
// x, y center point
double x, y;
double w, h;
~RectBounds(){ }
// (_x, _y): center of rectangle bound. (_w, _h): width and height
RectBounds(double _x, double _y, double _w, double _h){
x = _x;
y = _y;
w = _w;
h = _h;
}
//... more functions
};
I also have the following function structure:
void MyClass::init( BoundBases &bounds, std::vector<int> &colsPartitioned)
{
printf("init - new\n");
BoundBases * bPtr = &bounds;
RectBounds * rBounds = dynamic_cast<RectBounds *>(bPtr);
if(rBounds){
// do something
}else{
throw runtime_error("dynamic cast fail");
}
}
The dynamic cast is failing even though I call the function with RectBounds type as an argument. What is the reason?
FIXED:
The function calling init passed BoundBases by value, as follows:
MyClass2::MyClass2( BoundBases boundBases, std::vector<int> colsPartitioned) { // creates new table
// set up partition
partScheme_ -> setColsPartitioned(colsPartitioned);
partScheme_ -> setBoundBases(boundBases);
partScheme_ -> init(boundBases, colsPartitioned);
}
I changed the signature to pass by reference and it worked. (&boundBases). Can someone explain why is that? I am new to C/C++.
You need a reference here because dynamic_cast will only work if the real type of your variable is of type RectBounds like :
BoundBases* dummy = new Rectbound();
You can downcast here because the real type is Rectbound, so it will work.
If you pass it by value, it will create a copy of only the BoundBase part of your object, losing the information about your real type.
This problem is known as slicing
I'm not sure why you are surprised by that behavior. BoundBases passed by value is just a BoundBases. So dynamic_casting that to a child cannot make that a RectBounds. That's exactly what dynamic_cast is supposed to do.
If it worked differently: How would it be determining what e.g. x,y are if it's only given a BoundBases. This is not defined.
Hi i am trying to understand how to use the 'this' pointer. Now i wrote a sample program which uses a class Image which is a subclass of a class BMP. Now the functions TellWidth and TellHeight are declared in the BMP class. Now the compiler gives me an error which says that the TellWidth function does not exist in Image. But as Image is a subclass of BMP shouldnt it inherit the functions in BMP.
How do i resolve this
void Image :: invertcolors()
{
int x;
int y;
int width =(*this).TellWidth();
int height = (*this)->TellHeight();
for(x=0,x<=height-1;x++){
for(y=0,y<=width-1;y++){
(*this)(x,y)->Red = (255 - (*this)(x,y)->Red);
(*this)(x,y)->Blue = (255 - (*this)(x,y)->Blue);
(*this)(x,y)->Green = (255 - (*this)(x,y)->Green);
}
}
delete width;
delete height;
}
Image
class Image : public BMP
{
public:
void invertcolors();
void flipleft();
void adjustbrightness(int r, int g, int b) ;
};
This class is too big to post here, here is a relavent excerpt
class BMP {
private:
int Width;
int Height;
public:
int TellBitDepth(void) const;
int TellWidth(void) const;
int TellHeight(void) const;
};
TellWidth() is most likely declared as private (or has no accessor modifier) in the BMP class. It needs to be protected or public for the Image class to be able to access it, and it needs to be also virtual, if you want to be able to override it in the Image class.
And the proper this usage is like this:
int width = this->TellWidth();
int height = this->TellHeight();
Read this for a quick tutorial on this.
One point about this: you rarely need to mention it explicitly. The usual exception is when you need to pass it into a non-member function (which doesn't seem to be the case here.)
When you're inside of a class member function, this->field can be accessed simply as field, and this->function(x) can be invoked as function(x).
Here are some comments on your code. I hope they're helpful.
void Image :: invertcolors()
{
// Don't define these here; that's old C-style code. Declare them where
// they're needed (in the loop: for (int x=0...)
int x;
int y;
// Change the lines below to
// int width = TellWidth();
// int height = TellHeight();
// (*this).TellWidth() should work, but is redundant;
// (*this)->TellHeight() should probably *not* work, as once you've
// dereferenced *this, you're dealing with an object instance, not a
// pointer. (There are ways to make (*this)->that() do something useful,
// but you're probably not trying something like that.)
int width =(*this).TellWidth();
int height = (*this)->TellHeight();
for(x=0,x<=height-1;x++){
for(y=0,y<=width-1;y++){
// After locating the BMP class through google (see Edit 2),
// I've confirmed that (*this)(x,y) is invoking a (int,int) operator
// on the BMP class. It wasn't obvious that this operator
// was defined; it would have been helpful if you'd posted
// that part of the header file.
(*this)(x,y)->Red = (255 - (*this)(x,y)->Red);
(*this)(x,y)->Blue = (255 - (*this)(x,y)->Blue);
(*this)(x,y)->Green = (255 - (*this)(x,y)->Green);
}
}
// These are int values. They can't be deleted, nor do they need to be.
// I'm sure the compiler has told you the same thing, though perhaps not
// in the same way.
delete width;
delete height;
}
EDIT: Looks like there's someone else taking the same course as the OP. The example presented there makes it clearer that Image is supposed to have some sort of array accessor, which may explain what (*this)(x,y)->Red = (255 - (*this)(x,y)->Red) was intended to achieve.
EDIT 2: Here's the source for the original BMP class.
class Image is defined as
class Image : public BMP
{
public:
void invertcolors();
void flipleft();
void adjustbrightness(int r, int g, int b) ;
};