RTTI behavior not appearing as expected - c++

I have written this code in MS Visual Studio Express 2012 to see the rtti behavior.
But it is not working as expected.
What is wrong in my code?
Shape.h
class Shape
{
public:
Shape(){}
virtual ~Shape(){}
virtual double area() = 0;
};
class Square : public Shape
{
int a;
public:
~Square(){}
Square(int );
virtual double area();
};
class Rectangle : public Shape
{
int l;
int b;
public:
~Rectangle(){}
Rectangle(int,int);
virtual double area();
};
class Circle : public Shape
{
int r;
public:
~Circle(){}
Circle(int);
virtual double area();
};
ShapeMain.cpp
int main()
{
Shape* c = new Circle(4);
cout<< "Area of circle:" << c->area() << endl;
cout << typeid(c).name();
Shape* s = new Square(4);
cout<< "Area of square:" << s->area() << endl;
cout << typeid(s).name();
Shape* r = new Rectangle(4,5);
cout<< "Area of rectangle:" << r->area() << endl;
cout << typeid(r).name();
}
Output
Area of circle:50.24
class Shape * //Expected class Circle*
Area of square:16
class Shape * //Expected class Square*
Area of rectangle:20
class Shape * //Expected class Rectangle*

typeid() only actually performs an RTTI lookup when passed an lvalue of a polymorphic type. Shape is a polymorphic type, but you aren't passing a Shape lvalue, you're passing a Shape*. So when you are passing c, s and r to typeid(), it reports the static type of those expressions, which is Shape*.
To get a run time lookup you can either dereference your pointer: std::cout << typeid(*r).name() << std::endl;
or you can keep references directly:
Circle circle{4};
Shape& c = circle;
cout << "Area of circle:" << c.area() << endl;
cout << typeid(c).name() << endl;

Related

'class MainClass' has no member named 'procent

#include <iostream>
#include <vector>
using namespace std;
class MainClass{
public:
virtual void getData() = 0;
virtual void printData() = 0;
};
class Car : public MainClass{
private:
int hp;
int motor;
public:
Car(int _hp = 0, int _motor = 0){
hp = _hp;
motor = _motor;
}
~Car(){
cout << "The program is over";
}
void getData(){
cout << "HorsePower = ";
int _hp;
cin >> _hp;
hp = _hp;
cout << "Motor = ";
int _motor;
cin >> _motor;
motor = _motor;
}
void printData(){
cout << "HorsePower = " << hp << '\n';
cout << "Motor = " << motor << '\n';
}
float procent(){
return float(motor) / hp;
}
};
int main()
{
MainClass *p = new Car;
p -> getData();
p -> printData();
cout << p -> procent();
return 0;
}
I'm pretty new with oop concepts so why do I get the error from title and how can i solve it? I tried to put virtual float procent() = 0 in MainClass, but then i should use this function in every class that i would create next and I dont want this.
procent() is not a member of class MainClass.
The pointee type of p is MainClass.
Hence, you can only access what is known in MainClass.
That the pointer p actually holds an address of a Car instance doesn't count for this.
getData() and printData() are known but procent() not. (It's part of the derived class Car.)
That you can access Cars overridden getData() and printData() by the MainClass pointer p is a result of the (wonderful world of) polymorphy i.e. they are virtual.
So, this is a potential solution – to make procent() a virtual member function of MainClass as well.
There is still another solution but it should be used as last resort only:
You can use dynamic_cast() to check whether/that p holds actually a pointer to an instance of class Car:
#include <iostream>
#include <vector>
using namespace std;
class MainClass{
public:
virtual void getData() = 0;
virtual void printData() = 0;
};
class Car : public MainClass{
private:
int hp;
int motor;
public:
Car(int _hp = 0, int _motor = 0){
hp = _hp;
motor = _motor;
}
~Car(){
cout << "The program is over";
}
void getData(){
cout << "HorsePower = ";
int _hp;
cin >> _hp;
hp = _hp;
cout << "Motor = ";
int _motor;
cin >> _motor;
motor = _motor;
}
void printData(){
cout << "HorsePower = " << hp << '\n';
cout << "Motor = " << motor << '\n';
}
float procent(){
return float(motor) / hp;
}
};
int main()
{
MainClass *p = new Car;
p -> getData();
p -> printData();
if (Car *pCar = dynamic_cast<Car*>(p)) {
cout << pCar -> procent();
}
return 0;
}
Output:
HorsePower = 300
Motor = 6
HorsePower = 300
Motor = 6
0.02
Live Demo on coliru
The solution with dynamic_cast may be preferable for large class inheritance trees where it's merely impractical to add virtual member functions to the base class for any (exotic) specific feature of derived classes.
The error happens because your trying to access the procent() method in the MainClass object. To resolve this, you need to add it as a virtual method in the MainClass and override it in the Car object.
Plus make sure to delete the allocated memory.
#include <iostream>
#include <vector>
using namespace std;
class MainClass{
public:
virtual void getData() = 0;
virtual void printData() = 0;
virtual void procent() = 0;
};
class Car : public MainClass {
private:
int hp;
int motor;
public:
Car(int _hp = 0, int _motor = 0){
hp = _hp;
motor = _motor;
}
~Car(){
cout << "The program is over";
}
void getData() override {
cout << "HorsePower = ";
int _hp;
cin >> _hp;
hp = _hp;
cout << "Motor = ";
int _motor;
cin >> _motor;
motor = _motor;
}
void printData() override {
cout << "HorsePower = " << hp << '\n';
cout << "Motor = " << motor << '\n';
}
float procent() override {
return float(motor) / hp;
}
};
int main()
{
MainClass *p = new Car;
p -> getData();
p -> printData();
cout << p -> procent();
delete p;
return 0;
}
The reason for the error is that when you assign the data of the derived class to the base class pointer, the data accessed from the base class pointer is treated as if its from the base class. And since the method procent() is not available in it, the error is flagged.
TIP:
Even though stating override in the overridden method is not necessary, it'll definitely increase the readability of your code.

How to achieve Multilevel Inheritance with classes

I am trying to do some multilevel inheritance from the Shape class to Rectangle, Circle and Triangle classes. From Rectangle I need to inherit a Square class and print the area, info, etc.. as well as Ellipse from Circle and Isosceles from Triangle. So far my first inherited classes work fine, but whenever I try to make the "grandchildren" class work I cannot make it work. I have no idea what I might be doing wrong. Here is the code:
#include <iostream>
using namespace std;
class Shape{
protected:
string name;
float area;
public:
Shape(string nm):name(nm){}
//Getters
string getName(){ return name; }
float getArea(){}
//Setters
virtual void setArea(){}
//Print
virtual void printInfo()
{
cout << "Name: " << name << " Color: " << endl;
}
};
class Rectangle : public Shape{
private:
float length, width;
public:
Rectangle(string nm, float l, float w):Shape::Shape(nm), length(l), width(w){}
Shape::getName();
//Setters
void setArea(){ area = length*width; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " L: " << length << " W: " << width << " A: " << area << endl;
}
};
class Square : public Rectangle{
private:
float length;
public:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm){}
float getLength(){return length;}
//Setters
void setArea(){ area = length *length; }
};
class Circle : public Shape{
private:
float radius;
const float pi = 3.0;
public:
Circle(string nm, float r):Shape::Shape(nm), radius(r){}
//Setters
void setArea(){ area = pi*radius*radius; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " R: " << radius << " A: " << area << endl;
}
};
//class Ellipse : public Circle{
//
//private:
// float length, width, radius1, radius2;
//
//public:
// Ellipse(string nm, int clr, float l, float w);
//
// //Setters
//void setArea(){ area = radius1 * radius2; }
//
//};
class Triangle : public Shape{
private:
float a, base, c, height;
public:
Triangle(string nm, float a, float b, float c, float h):Shape::Shape(nm), a(a), base(b), c(c), height(h){}
//Setters
void setArea(){ area = (base*height)/2; }
void printInfo(){
//Shape::printInfo();
cout << "Name: " << name << " Color: " << " A: " << a << " Base: " << base << " C: " << c << " H: " << height << " P: " << " A: " << area << endl;
}
};
//class Isosceles : public Triangle{
//
//private:
// float base, height;
//
//public:
// Isosceles(string nm, int clr, float l, float w);
//
// //Setters
// void setArea(){ area = (base*height)/2; }
//
//};
int main() {
Rectangle r("Rectangle", 10, 20);
Circle c("Circle", 1);
Triangle tt("Triangle", 2, 2, 3, 3);
Square ss("Square", 10);
Shape* s;
Shape* t;
Shape* u;
Shape* v;
s = &r;
t = &c;
u = &tt;
v = &ss;
//Set and print area of Rectangle
s->setArea();
s->printInfo();
//Set and print area of Circle
t->setArea();
t->printInfo();
//Set and print area of Triangle
u->setArea();
u->printInfo();
//Set and print area of Rectangle
v->setArea();
v->printInfo();
return 0;
}
I get an error while setting up the Square class over here:
class Square : public Rectangle{
private:
float length;
public:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm){}
I commented out the Ellipse and Isosceles classes just so I could set up correctly Square and work no them later.
This is my first time asking something, so if something is not correct please let me know.
Thank you for your help.
In your Square class I believe I found one mistake...
Try doing the following with your square constructor:
Square(string nm, float l):length(l),Rectangle::Rectangle(nm, l, l){}
As opposed to what you had... that will fix the errors you are getting with the Square class.
The reason for the difference is because when you were passing arguments to the Rectangle constructor from the Square constructor you were leaving some arguments unintialized (in the Rectangle constructor).

Accessing member functions through pointers

Why am I getting the address in the output. Rather I should get the Output Length= (value input by user) , Width = (value input by user).
As in the main body of program after getting input R1.getdata() , ptr->result() should display the result of Rectangle class.
#include <iostream>
using namespace std;
class Rectangle {
protected:
float length;
float width;
public:
void getdata() {
cout << "Enter length and width= ";
cin >> length >> width;
}
void result() {
cout << "Length = " << length << "\nWidth = " << width << endl;
}
};
class Area : public Rectangle {
private:
float area;
public:
void calc_area() { area = length * width; }
void result() { cout << "Area = " << area << endl; }
};
class Perimeter : public Rectangle {
private:
float perimeter;
public:
void calc_peri() { perimeter = 2 * (length + width); }
void result() { cout << "Perimeter = " << perimeter << endl; }
};
void main() {
Rectangle R1;
Area A1;
Perimeter P1;
Rectangle *ptr;
R1.getdata();
ptr = &A1;
ptr->result();
}
You are getting the wrong values, because you are calling ptr->result(); on a uninitialized Area object (A1), which has been upcasted from pointer to Rectangle object.
The values the user inputs though are used in the R1 object, which you then don't use anymore. Moreover, you should make the result() method virtual.
Lastly, the syntax for calling base class method on a pointer to an inheriting class is: ptr->Rectangle::result();.
Below you will find your code with some fixes that demonstrate things I wrote about:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Rectangle {
protected:
float length;
float width;
public:
void getdata() {
cout << "Enter length and width= ";
cin >> length >> width;
std::cout << length << " " << width << std::endl;
}
virtual void result() {
cout << "(Rectangle) Length = " << length << "\nWidth = " << width
<< endl;
}
};
class Area : public Rectangle {
private:
float area;
public:
void calc_area() { area = length * width; }
void result() { cout << "Area = " << area << endl; }
};
class Perimeter : public Rectangle {
private:
float perimeter;
public:
void calc_peri() { perimeter = 2 * (length + width); }
void result() { cout << "Perimeter = " << perimeter << endl; }
};
int main() {
Rectangle R1;
Area* A1;
Perimeter P1;
Rectangle* ptr;
R1.getdata();
ptr = &R1;
A1 = static_cast<Area*>(ptr);
// or:
// A1 = (Area*)ptr;
ptr->Rectangle::result();
}
Ptr points to the address of a child of class Rectangle (the Area class) and therefore it calls the member (result) of the object it refers to (A1 of type Area)

C++ test with classes

Im trying to solve a problem in C++ but because im a begginer i dont know how to do it !
The problem is this if you can help me :) :
By using the below C++ code create the proper constructor functions about the classes "car" & "truck". Each function must pass the appropriate arguments to the parent class of vehicle.Additionally, the function car should initialize the passengers when creating an object. The truck class should initialize the loadlimit when creating an object.
The statement of objects with the car () and truck () will be as follows:
car ob(passengers, wheels, range);
truck ob(loadlimit, wheels, range);
#include <iostream>
using namespace std;
class vehicle{
int num_wheels;
int range;
public:
vehicle(int w, int r){num_wheels = w; range = r;}
void showv(){
cout << "Wheels: " << num_wheels << endl;
cout << "Range: " << range << endl;
}
};
class car : public vehicle {
int passengers;
public:
void show(){
void showv();
cout << "Passengers: " << passengers << endl;
}
};
class truck : public vehicle {
int loadlimit;
public:
void show(){
void showv();
cout << "Loadlimit: " << loadlimit << endl;
}
};
int main(){
car c(5, 4, 500);
truck t(3000, 12, 1200);
cout << "Car: " << endl;
c.show();
cout << "Truck: " << endl;
t.show();
return 0;
}
Class Car and Truck does not have constructors that take required parameters and pass to the base class's constructor. they should be like this:
class car : public vehicle {
int passengers;
public:
car(int w,int r,int p): vehicle(w,r), passengers(p){}
void show(){
void showv();
cout << "Passengers: " << passengers << endl;
}
};
class truck : public vehicle {
int loadlimit;
public:
truck(int r, int w, int l):vehicle(r,w),loadlimit(l){}
void show(){
void showv();
cout << "Loadlimit: " << loadlimit << endl;
}
};
Base member initialisation
Car Constructor:
car(int a, int b, int c) : vehicle(a,b),passengers(c){}; //initialiser list
Truck Constructor:
truck(int g, int h, int j):vehicle(g,h),loadlimit(j){}
You need to add a Contractor to car and truck
class car : public vehicle {
int passengers;
public:
car(int p) : vehicle(int w, int r) // Call the superclass constructor in the subclass'
{
passengers = p;
}
void show()
{
showv();
cout << "Passengers: " << passengers << endl;
}
};
The same thing for Truck
Simple Solution,
car::car(int w,int r,int p)
{
passengers = p;
vehicle::vehicle(w,r);
}

Object of abstract class type "Rectangle" is not allowed

//QuizShape.h
#ifndef QUIZSHAPE_H
#define QUIZHAPE_H
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class QuizShape
{
protected:
//outer and inner symbols, and label
char border, inner;
string quizLabel;
public:
//base class constructor with defaults
QuizShape(char out = '*', char in = '+', string name = "3x3 Square")
{
border = out;
inner = in;
quizLabel = name;
cout << "base class constructor, values set" << endl << endl;
};
//getters
char getBorder() const
{ return border; }
char getInner() const
{ return inner; }
string getQuizLabel() const
{ return quizLabel; }
//virtual functions to be defined later
virtual void draw( ) = 0;
virtual int getArea( ) = 0;
virtual int getPerimeter( ) = 0;
};
class Rectangle : public QuizShape
{
protected:
//height and with of a rectangle to be drawn
int height, width;
public:
//derived class constructor
Rectangle(char out, char in, string name,
int h = 3, int w = 3):QuizShape(out, in, name)
{
height = h;
width = w;
cout << "derived class constructor, values set" << endl << endl;
}
//getters
int getHeight() const
{ return height; }
int getWidth() const
{ return width; }
//*********************************************
virtual void draw(const Rectangle &rect1)
{
cout << "draw func" << endl;
cout << rect1.height << endl;
cout << rect1.getWidth() << endl;
cout << rect1.getQuizLabel() << endl;
}
virtual int getArea(const Rectangle &rect2)
{
cout << "area func" << endl;
cout << rect2.getInner() << endl;
cout << rect2.getBorder() << endl;
}
virtual int getPerimeter(const Rectangle &rect3)
{
cout << "perim func" << endl;
cout << rect3.height << endl;
cout << rect3.getWidth() << endl;
cout << rect3.getQuizLabel() << endl;
}
//************************************************
};
#endif
These are the class types so far.
//QuizShape.cpp
#include "QuizShape.h"
This currently does nothing but bridge the files.
//pass7.cpp
#include "QuizShape.cpp"
int main()
{
Rectangle r1('+', '-', "lol", 4, 5);
cout << r1.getHeight() << endl;
cout << r1.getWidth() << endl;
cout << r1.getInner() << endl;
cout << r1.getBorder() << endl;
cout << r1.getQuizLabel() << endl;
system("pause");
return 0;
}
The code will not compile due to the fact that Rectangle is supposedly an abstract class, and when hovering over the declaration of r1 in main, I receive the error
"Object of abstract class type "Rectangle" is not allowed".
I have checked other answers on this site and others and have not come across something that solves the problem.
NOTE: I understand that the statements for virtual functions ending in =0; cause the class to become an abstract one. QuizShape SHOULD be abstract. I have defined the virtual functions in Rectangle and yet it remains an abstract class.
How can I modify the virtual functions Rectangle class so that Rectangle is no longer abstract?
Your methods int the abstract class QuizShape are:
virtual void draw( ) = 0;
virtual int getArea( ) = 0;
virtual int getPerimeter( ) = 0;
but in Rectangle they take const Rectangle &rect1 as parameter so you shadowing the methods and not overriding the abstract one at all. You need to have methods in Rectangle with the same signature as the ones in the abstract base class.
The overridden methods must have the exact same signature, in the derived class you have given them arguments.