Why use getters to const private members instead of making them public? - c++

Suppose I have a simple class that defines a Circle object:
class Circle {
public:
Circle(const double x): radius(x) { ; }
const double getRadius() const { return radius; }
private:
const double radius;
};
This seems like a common convention and subscribes to the OO principle of data-hiding. My question is why do this? Would it not be simpler to make radius a public member? For a mutable member, this would obviously be a bad idea, since anyone could modify the circle's radius, but since it's const, I see no need to make it private. Would it be acceptable to do something like this?:
class Circle {
public:
Circle(const double x): radius(x) { ; }
const double radius;
};

Related

c++ non-member function using a class which references another class

I have this HW question that I have been stuck for hours on that I can't seem to make sense of. It's kind of hard to put to words my actual question but I will try my best. How can I make my outside-member function find the distance between a circle using a class which references another class? In my code below:
//Header
class Point
{
public:
Point();
Point(int, int);
Point(const Point& object);
int getX() const;
int getY() const;
void setX(int);
void setY(int);
double calculate_area();
void print() const;
private:
int x;
int y;
};
class Shape
{
public:
Shape();
double calculate_area();
void print() const;
protected:
double area;
};
class Circle : public Shape
{
public:
Circle();
Circle(const Point&, double);
double getRadius() const;
void setRadius(double);
void calculate_area();
void print() const;
private:
double radius;
Point center;
};
class RTriangle : public Shape
{
public:
RTriangle();
RTriangle(double, double);
double hyp();
void calculate_area();
void print() const;
private:
double side1;
double side2;
};
inline double distance(Circle& other)
{
return sqrt(pow(other.center.x, 2) + pow(other.center.y, 2));
}
#endif
//Implementation.cpp of what i think is important for you guys to see
Point::Point(int inX, int inY) // normal constructor
{
x = inX;
y = inY;
}
Point::Point(const Point &object) // copy constructor needed to use for center of circle
{
x = object.x;
y = object.y;
}
Circle::Circle(const Point& object, double inRad) // center is x & y... radius for circle
{
center = object;
radius = inRad;
}
My outside member function (inline double distance) isn't working. This is the first time I have tried doing this so I apologize if I do not word it well. I am essentially trying to use only the Circle class which inherits point center and point center is defined in the first class as x and y. Is it possible to do such a thing (specifically use x and y which is inside Point center)? I don't know if it's possible to access x and y through center.
Given a Point, functions not in Point can access its x and y members with the public getX() and getY() methods in your example.
However, Circle's center member is not public and has no public accessors. The most straightforward fix would add a public method
Point getCenter(); // or Point const &getCenter() if you like)
to Circle.

c++ polymorphism - passing a reference to base class to a function

I'm learning about c++ polymorphism. In the code below, a pointer called shape of the type of the base class Shape is creates and then pointed at the objects r and c.
The functions printArea(r); and printArea(c); are then called. However, at the point that these functions are called shape is pointing to the address of c. So how does it work when you call printArea(r);?
#include<iostream>
using namespace std;
class Shape {
public:
virtual float getArea() const = 0;
};
class Rectangle : public Shape {
private:
float width;
float height;
public:
Rectangle(float width, float height) : width(width), height(height) {}
float getArea() const {return width * height;}
};
class Circle : public Shape {
private:
float radius;
public:
Circle(float radius) : radius(radius) {}
float getArea() const {return 3.14159f * radius *radius;}
};
void printArea(const Shape& shape) {
std::cout << "Area: " << shape.getArea() << std::endl;
}
int main() {
Rectangle r(2,6);
Shape* shape = &r;
Circle c(6);
shape = &c;
printArea(r);
printArea(c);
printArea(*shape);
return 0;
}
I would guess your question is how, technically, is the call to getArea dispatched at run time.
The C++ standard does not prescribe this. It prescribes exactly which implementation must be executed, but not how that is accomplished.
Nearly all extant C++ implementations do that by placing a hidden pointer in each object of class with one or more virtual functions. That hidden pointer points to a table of function pointers, namely pointers to the virtual methods of the class of the object's dynamic type. This is called a vtable. And in general the call is dispatched by checking the object's vtable pointer, and retrieving the function pointer from the getArea item in the vtable, and calling that function.
There are complications for multiple inheritance, but those are just that: complications.
An alternative could be to search up the base class chain for each call.
That would be less efficient but still it's been used, at least in other languages, e.g. in original Smalltalk, and in Borlands GUI class framework for Pascal in Windows in the 1990s.
Another alternative is to place pointers to each virtual function directly in each object, essentially a vtable in each object. That approach is sometimes used in C. The main advantage is that it's conceptually simple. It also avoids one indirection. But it wastes space and doesn't generalize very well.
#include<iostream>
using namespace std;
class Shape {
public:
virtual float getArea() const = 0;
};
class Rectangle : public Shape {
private:
float width;
float height;
public:
Rectangle(float width, float height) : width(width), height(height) {}
float getArea() const {return width * height;}
};
class Circle : public Shape {
private:
float radius;
public:
Circle(float radius) : radius(radius) {}
float getArea() const {return 3.14159f * radius *radius;}
};
void printArea(const Shape& shape) {
std::cout << "Area: " << shape.getArea() << std::endl;
}
int main() {
Rectangle r(2,6);
Shape* shape = &r; // shape stores the address of object r which when further call
std::cout<< shape <<endl; //called sends its address
Circle c(6);
shape = &c; // same as r is being processed
std::cout<<shape<<endl;
printArea(r); // same thing is taking place here reference is passed and then polymorphism come
printArea(c); // into play
printArea(*shape); // as the shape was given reference of c in the end it returns its value
return 0;
}
if u still have any questions feel free to ask in comments!

C++ inheritance and virtual funcions

Here is my task:
Design classes Circle and Square which are inherited from class Shape (which contains center of gravity which is common characteristic for all shapes, function for moving center of gravity for specific value and virtual functions circumference, area and read). Classes should have specific functions for calculating circumference and area, as well as for reading data members.
Here is what I have done:
#include <iostream>
using namespace std;
class Point {
private:
float x;
float y;
public:
Point();
Point(float,float);
~Point();
};
Point::Point() {
}
Point::Point(float a,float b) {
x=a;
y=b;
}
Point::~Point() {
}
class Shape {
public:
Shape(void);
Shape(Point);
virtual float circumference(void) {}
virtual float area(void) {}
protected:
Point center_of_gravity;
};
Shape::Shape(void) {
}
Shape::Shape(Point a) {
center_of_gravity=a;
}
//----------------------------------------
class Circle:public Shape {
private:
float radius;
public:
float x;
float y;
Circle();
Circle(float);
virtual float circumference(void);
virtual float area(void);
};
Circle::Circle(void) {
}
Circle::Circle(float a) {
radius=a;
}
float Circle::area(void) {
float area_of_circle;
const float pi=3.14159;
area_of_circle=radius*radius*pi;
return area_of_circle;
}
float Circle::circumference(void) {
float circumference_of_circle;
const float pi=3.14159;
circumference_of_circle=2*radius*pi;
return circumference_of_circle;
}
//----------------------------------------
class Square:public Shape {
private:
float length;
public:
Square();
Square(float);
virtual float circumference(void);
virtual float area(void);
};
Square::Square(void) {
}
Square::Square(float a) {
length=a;
}
float Square::area(void) {
float area_of_circle;
area_of_circle=length*length;
return area_of_circle;
}
float Square::circumference(void) {
float circumference_of_square;
circumference_of_square=4*length;
return circumference_of_square;
}
int main() {
float a,b;
cout<<"Enter coordinates of center of gravity: "<<endl;
cin>>a>>b;
Point center_of_grav(a,b);
cout<<"Enter length of square: "<<endl;
cin>>a;
Square square(a);
cout<<"Enter radius of circle: "<<endl;
cin>>a;
Circle circle(a);
Shape *shape1=&circle;
Shape *shape2=&square;
cout<<"Area of circle is "<<shape1->area()<<", circumference is "<<shape1->circumference()<<endl;
cout<<"Area of square is "<<shape2->area()<<", circumference is "<<shape2->circumference()<<endl;
}
Is it ok? How can I realize function for moving center of gravity?
How can I read center of gravity for Circle and Square (it is inherited from class Shape)? They mean it (I think) when they say "...as well as for reading data members."
EDIT:
After I put all suggestion I got in one place:
#include <iostream>
using namespace std;
class Point{
private:
float x;
float y;
public:
Point();
Point(float,float);
~Point();
friend class Shape;
};
Point::Point(){
}
Point::Point(float a,float b){
x=a;
y=b;
}
Point::~Point(){
}
//----------------------------------------
class Shape{
public:
Shape(void);
Shape(Point);
virtual float area(void)=0;
virtual float circumference(void)=0;
protected:
float x_coordinate;
float y_coordinate;
Point center_of_gravity;
};
Shape::Shape(void){
}
Shape::Shape(Point a){
center_of_gravity=a;
x_coordinate=a.x;
y_coordinate=a.y;
}
//----------------------------------------
class Circle:public Shape{
private:
float radius;
public:
Circle();
Circle(Point,float);
virtual float area(void);
virtual float circumference(void);
};
Circle::Circle(void){
radius=0;
}
Circle::Circle(Point p,float a) : Shape(p), radius(a){
}
float Circle::area(void){
float area_of_circle;
const float pi=3.14159;
area_of_circle=radius*radius*pi;
return area_of_circle;
}
float Circle::circumference(void){
float circumference_of_circle;
const float pi=3.14159;
circumference_of_circle=2*radius*pi;
return circumference_of_circle;
}
//----------------------------------------
class Square:public Shape{
private:
float length;
public:
Square();
Square(Point,float);
virtual float area(void);
virtual float circumference(void);
};
Square::Square(void){
length=0;
}
Square::Square(Point p,float a) : Shape(p), length(a){
}
float Square::area(void){
float area_of_circle;
area_of_circle=length*length;
return area_of_circle;
}
float Square::circumference(void){
float circumference_of_square;
circumference_of_square=4*length;
return circumference_of_square;
}
//----------------------------------------
int main(){
float a,b;
cout<<"Enter coordinates of center of gravity: "<<endl;
cin>>a>>b;
Point center_of_grav(a,b);
cout<<"Enter length of square: "<<endl;
cin>>a;
Square square(center_of_grav,a);
cout<<"Enter radius of circle: "<<endl;
cin>>a;
Circle circle(center_of_grav,a);
Shape *shape1=&circle;
Shape *shape2=&square;
cout<<"Area of circle is "<<shape1->area()<<", circumference is "<<shape1->circumference()<<endl;
cout<<"Area of square is "<<shape2->area()<<", circumference is "<<shape2->circumference()<<endl;
}
1.Constructor design
How will you set their gravity center ?
Point center_of_grav(a,b);
...
Square square(c); // what's the gravity center ?
You have to design the constructor of the derived, so that it has all information required to construct the base:
Square square(center_of_grav, c);
To achieve this, you have to define it in the following way (of course adapt the class definition accordingly):
Square::Square(Point p, float a) : Shape(p), lentgh(a) {
// ... reserve this for more complex initisalisations
}
Note that your default constructor leave the objects uninitialized.
2.Design of Shape
Very important: Shape is a polymorphic class with virtual functions. You shall take the habit to define a virtual destructor in this case.
Minor remark: It makes no sense to create directely a Shape object. It's an abstract concept. There is no default rule to calculate an area or a circumference that could apply to most of the shape. Therefore, I'd strongly suggest to define these two functions as pure virtual:
class Shape {
...
virtual float circumference(void) =0; // pure virtual
virtual float area(void) = 0;
...
};
Advantage: as soon as you have a pure virtual function in a class, this class becomes abstract, and you won't be able to instantiate an object of that class by error. The compiler will make sure that you instatiate only concrete derivates of the abstract concept.
3.Make sure your code complies with requirements
Well it's a detail and you certainly have taken care of it, but:
Classes should have specific functions for calculating circumference
and area, as well as for reading data members.
So I think you should foresee some getters to access to the protected data:
Example:
class Shape {
...
Point get_gravity_center();
...
};
Point Shape::get_gravity_center() {
return center_of_gravity;
}
I let you complete the others. Simply imagine that you have to print in main() the description of a circle (coordinates of the center and radius), and you'll see the getters that are missing.
Edit following your question:
As you we've defined the getter for the center of gravity at the shape level, you don't need to define it again in the derivates. You could then simply call it in main(). The problem is that you also need to access to the coordinats of that point. So:
class Point {
...
float get_x() { return x; }
float get_y() { return y; }
...
};
With this you can write in main():
cout << "Circle of center ("<<circle.get_gravity_center().get_x()<<","
<< circle.get_gravity_center().get_y()<<")"<<endl;
P.S: with the center_of_gravity as member of shape, you no longer need to duplicate the coordinates otf that point.
To answer your question, it is not OK. Your code does show some pretty clear thinking, so that's good. It just needs to be finished. All data members of all classes must be given values when objects are constructed. Otherwise, they get random values, and that is never good practice. So init the CG in the Shape constructor.
Also, remove x and y from circle, if you mean them to represent CG -- that info is inherited already.
Finally, to realize a function for moving CG, I'd recommend adding a setter method to the Shape class, where it can be inherited by those other two classes. With that, you should be good to go.

How to call different derived classes in constructors of classes derived from a different base class

In C++, I have two separate base classes, each of whose derived classes are somewhat coupled. Here's an example for the kind of thing I'd like to do:
First define a set of classes, e.g.,:
class Shape
{
public:
double area;
double diameter;
};
class Rectangle : public Shape
{
public:
double width;
double height;
};
class Circle : public Shape
{
public:
double radius;
};
The second set of classes then pertains to operations being performed on this first set of classes, something like this:
class Calculator
{
public:
static Calculator *create_calculator(shape *shape,const char *shape_type); // the factory
virtual void calculate()=0; // the actual calculation
};
class area_circles : public Calculator
{
class circles *circle;
public
area_circles(circles *circle)
{
this->circle = circle;
}
void calculate()
{
this->area = PI*pow(circle->radius,2);
}
}
class area_rectangles : public Calculator
{
class rectangles *rectangle;
public
area_rectangles(rectangles *rectangle)
{
this->rectangle = rectangle;
}
double calculate()
{
this->area = rectangle->height * rectangle->width;
}
}
Calculator *Calculator::create_calculator(shape *shape, const char *shape_type)
{
if (shape_type=="circle")
return new area_circles(shape);
if (shape_type=="rectangle")
return new area_rectangles(shape);
}
Then, the idea would be to call all this using something like:
rectangles *my_rectangle;
Calculator *area_calculator;
area_calculator = area_calculator->create_calculator(my_rectangle, "rectangle");
area_calculator->calculate();
However, this doesn't compile and I get an error (quite sensibly) pointing out how the Shape class has no member "width", and that "a value of type "shape *" cannot be assigned an entity of type "rectangles". The error's pretty clear on why this code isn't working.
Would anyone know how to get the code here to do what I'm trying to do?
From a design perspective, I recognize that part of the problem is that the derived classes end up being coupled, so maybe there is a better way to try to decouple the calculator class from the shape class. But I'd like to at least try out this approach for a while as well in my implementation, and for that I need the code to compile.
I am not entirely sure what you are trying to achieve here but I think the more usual approach to it is something like this:
class Shape
{
public:
virtual ~Shape() {}
// concrete classes must implement this function
virtual double get_area() const = 0;
};
class Circle
: public Shape
{
double diameter;
public:
Circle(double diameter): diameter(diameter) {}
virtual double get_area() const
{
return M_PI * diameter * diameter / 4;
}
};
class Rectangle
: public Shape
{
double width;
double height;
public:
Rectangle(double width, double height): width(width), height(height) {}
virtual double get_area() const
{
return width * height;
}
};
int main()
{
Circle c(2);
Rectangle r(20, 40);
// use Shape references (or pointers) to invoke polymorphic behaviour
Shape& cs = c;
Shape& rs = r;
std::cout << "Area of circle : " << cs.get_area() << '\n';
std::cout << "Area of rectangle: " << rs.get_area() << '\n';
}

c++ how differentiate between base classes in a derived class?

I understand this isn't the best title but I'm not sure how to explain this problem that I'm having without examples.
I have a base class (called vector3)
class vector3 {
protected:
double x,y,z;
public:
vector3(): x(0),y(0),z(0) {}
vector3(double xin, double yin, double zin): x(xin),y(yin),z(zin) {}
~vector3() {}
//...other stuff
};
Then I have another class, derived from vector3, called vector4:
class vector4 : public vector3 {
protected:
double ct;
public:
vector4(): vector3(0,0,0), ct=0 {}
vector4(double ctin): ct(ctin) {}
vector4(double ctin, double xin, double yin, double zin):
vector3(xin, yin, zin), ct(ctin) {}
vector4(double ctin, vector3 v):
vector3(v.getx(), v.gety(), v.getz()), ct(ctin) {}
~vector4() {}
//...more other stuff
};
And that's all fine, but now I've got a class called particle defined like this:
class particle : public vector4 {
protected:
//vector4 r;
double mass;
//vector3 beta;
public:
particle(): vector4(0,0,0,0), mass=0, vector3(0,0,0) {}
particle(vector4 rin, double massin, vector3 betain):
vector4(rin.getx(),rin.gety(),rin.getz(),rin.getct()),
mass=0,
vector3(betain.getx(),betain.gety(),betain.getz()) {}
~particle() {}
//...Further stuff
};
So now the question is:
How do I return the x value, y value and z value of the particle's position, and the x value, y value and z value of the particle's beta vector inside a function in the particle class?
With vector 4 I'd just do:
double getx() const {
return x;
}
double gety() const {
return y;
}
etc, but what would I use in the particle's class?
Position and beta vector are attributes of a particle, so you should be using aggregation instead of inheritance:
class particle {
protected:
vector4 r;
double mass;
vector3 beta;
// ...
You should only use inheritance where there is an is-a relationship between the subclass and superclass.
In your case, particle is a vector4, so you can define your getters public in vector4, and directly call particle.getX()
However, this does not seem to be a good idea, in my opinion, particle should contain a vector since it is not a specialisation of the vector4 class.
so let's say particle has a vector called _vector
you can define a method like this :
double getX(void) const
{
return (_vector.getX());
}
Same goes for getY