User defined type conversions in C++ - c++

I'm new to C++
below is the code for converting object of english distance(feet' inches") to meters and vice versa
#include <iostream>
using namespace std;
class Distance
{
private:
const float MTF;
int feet;
float inches;
public:
Distance() : feet(0), inches(0.0), MTF(3.280833F) //no argument constructor
{ }
Distance(float meters) : MTF(3.28033F)//(1-arg constructor)
{//coverting metres to distance object
float fltfeet = MTF * meters;
feet = int(fltfeet);
inches = 12*(fltfeet-feet);
}
Distance(int ft, float in) : feet(ft), inches(in), MTF(3.280833F)
{ }
void getdist()//get distance from user
{
cout << "\nEnter feet: "; cin >> feet;
cout << "Enter inches: "; cin >> inches;
}
void showdist() const // o/p the distance
{ cout << feet << "\'-" << inches << '\"'; }
operator float() const //conversion operator
{ // converts distance to meters
float fracfeet = inches/12;
fracfeet += static_cast<float>(feet);
return fracfeet/MTF;
}
};
int main()
{
float mtrs;
Distance dist1 = 2.35F; //meters to distance
cout << "\ndist1 = "; dist1.showdist();
mtrs = static_cast<float>(dist1); //casting distance to meters
cout << "\ndist1 = " << mtrs << " meters\n";
Distance dist2(5, 10.25);
mtrs = dist2; //casting dist2 to meters
cout << "\ndist2 = " << mtrs << " meters\n";
Distance dist3; //new object dist3
dist3 = mtrs; //here is the error
//not converting meters to distance object
cout<<"\ndist3 = ";dist3.showdist();
return 0;
}
but the code shows the error :
In member function 'Distance& Distance::operator=(const Distance&)':
error: non-static const member 'const float Distance::MTF', can't use default assignment operator
should'nt it be converting mtrs to object dist3 ?
why error occurs?

You error is actually with the line
dist3 = mtrs;
not
Distance dist3;
The reason for this is Distance has a const member variable. Since it is const it cannot be assigned to which cause the default copy assignment and move assignment operators to be deleted.
You are going to have to rethink your design if you want to allow assignment of your objects or write your own custom assignment functions.

You have to override assignment operator. And the code should be as shown below
#include <iostream>
using namespace std;
class Distance
{
private:
const float MTF;
int feet;
float inches;
public:
Distance() : feet(0), inches(0.0), MTF(3.280833F)
{ }
Distance(float meters) : MTF(3.28033F)
{
float fltfeet = MTF * meters;
feet = int(fltfeet);
inches = 12*(fltfeet-feet);
}
Distance(int ft, float in) : feet(ft), inches(in), MTF(3.280833F)
{ }
void getdist()
{
cout << "\nEnter feet: "; cin >> feet;
cout << "Enter inches: "; cin >> inches;
}
void showdist() const
{ cout << feet << "\'-" << inches << '\"'; }
operator float() const
{
float fracfeet = inches/12;
fracfeet += static_cast<float>(feet);
return fracfeet/MTF;
}
Distance& operator=(const Distance & otherD)
{
feet = otherD.feet;
inches = otherD.inches;
return *this;
}
};
int main()
{
float mtrs;
Distance dist1 = 2.35F;
cout << "\ndist1 = "; dist1.showdist();
mtrs = static_cast<float>(dist1);
cout << "\ndist1 = " << mtrs << " meters\n";
Distance dist2(5, 10.25);
mtrs = dist2;
cout << "\ndist2 = " << mtrs << " meters\n";
Distance dist3; //here is the error
dist3 = (Distance)mtrs ;
//cout<<"\ndist3 = ";dist3.showdist();
return 0;
}
Like another user said, you have a "const" variable, so you have to override assigment operator to address your requirements.

If you want to have class scope constant, you better change your class definition to:
class Distance
{
private:
static constexpr float MTF = 3.280833F;
int feet;
float inches;
public:
Distance() : feet(0), inches(0.0)
...
This will eliminate error you get and will work as you intended. Plus you do not have to define that constant value multiple times as you have in your code.
Note: if you cannot use C++11 you can make MTF global constant (better in unnamed namespace inside cpp file) or just static member. Either way it will eliminate the error and you will need to define it only once, which is less error prone.

I gather that the error comes at the line
dist3 = mtrs;
The problem here is that Distance does not have an assignment operator that takes an argument of type float, so the compiler tries to create a temporary object of type Distance and construct it with the argument mtrs; that's okay, but the next step is to assign that temporary value to dist3, and the compiler is complaining that it can't assign the value of MTF in the temporary object to the value of MTF in dist3 because MTF is const.
Because of that const, objects of type Distance cannot be assigned. So, for example, dist3 = dist2 would also fail. That's probably not what you intended, and you can fix this by adding an assignment operator that simply ignores the value of MTF.

The error occurs, because you could not declare const inside a class. You should define the const variable outside the class. You should replace const float MTF with float MTF here.

As stated in other answers, the issue is that you have declared the MTF variable as const. There are ways around this though. You've set the variable to be const because it's a constant and shouldnt change. Instead, add a dedicated Distance& operator=(float feet) Method in which you actually set the feet and inches variable when passed in a float value:
class Distance
{
private:
/* ... */
public:
/* ... */
Distance& operator=(float feet)
{
// Set the feet and inches here from
// the passed feet variable
return *this;
}
};
That should solve the problem of assigning the variable from a float.

Related

C++ Child struct with different variable names than parent

I made a 3d vector class like this
struct Vector3D {
float x;
float y;
float z;
Vector3D() {
x = 0;
y = 0;
z = 0;
}
Vector3D(float x1,float y1,float z1=0) {
x = x1;
y = y1;
z = z1;
}
//member functions for operator overloading, dot product, etc.
};
But now I want to make a child class specific to Euler angles. So far I have
struct Euler3D : Vector3D {
float roll;
float pitch;
float yaw;
};
How do I make the class so that roll pitch and yaw reference the same data as x, y and z? I think it involves union or something.
I want to be able to achieve something like this:
Euler3D a = {1, 2, 3};
cout << a.x << endl; // prints 1
a.x = 1.5;
cout << a.roll << endl; //prints 1.5
Thank you
How do I make the class so that roll pitch and yaw reference the same data as x, y and z?
You cannot.
Since you want to refer to an object, you could use reference instead, but that breaks copying - you can fix copy constructor by using user defined one. Furthermore (just like your duplication) this introduces unnecessary memory overhead.
What you can do is write a function that returns reference to the member. like this:
struct Euler3D : Vector3D {
float& roll() { return x; }
But this is not ideal either because you probably need at least a second set of overloads for const, so plenty of boilerplate.
I think it involves union or something.
You can use an union to have aliased members, but then you cannot have the inheritance. This is allowed:
struct Euler3D {
union { float x, roll; };
union { float y, pitch; };
union { float z, yaw; };
};
Which you can use exactly as in your snippet.
How do I make the class so that roll pitch and yaw reference the same
data as x, y and z?
The clue is in the word "reference" - you can make the members of the derived class references to the corresponding members in the base.
EDIT: As pointed out in the comments, this will also require the class to have a copy constructor:
struct Euler3D : Vector3D {
float& roll = Vector3D::x; // You don't actually need the "Vector3D::" ...
float& pitch = Vector3D::y; // ... qualifiers here, but using them adds ...
float& yaw = Vector3D::z; // ... clarity for more complex cases.
Euler3D() { } // Should have def. ctor as we define the copy!
Euler3D(const Euler3D& rhs) : Vector3D(rhs) { }
};
Here's a short piece of code to illustrate how this could work:
int main()
{
Euler3D* e3d = new Euler3D;
e3d->roll = 1.1f;
e3d->pitch = 2.2f;
e3d->yaw = 3.3f;
Vector3D* v3d = dynamic_cast<Vector3D*>(e3d);
std::cout << v3d->x << " " << v3d->y << " " << v3d->z << std::endl;
Euler3D e3d2 = *e3d;
std::cout << e3d2.roll << " " << e3d2.pitch << " " << e3d2.yaw << std::endl; // Copied from RHS
e3d2.roll = 4.4f; e3d2.pitch = 5.5f; e3d2.yaw = 6.6f;
std::cout << e3d2.roll << " " << e3d2.pitch << " " << e3d2.yaw << std::endl; // Changed
std::cout << v3d->x << " " << v3d->y << " " << v3d->z << std::endl; // Not changed
return 0;
}

Assignment operator overloading: returning void versus returning reference parameter [duplicate]

This question already has answers here:
Why should the assignment operator return a reference to the object?
(4 answers)
Closed 6 years ago.
Some of the assignment overloading operator examples I see online look like this:
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void operator = (const Distance &D ) {
cout << "assigning..." << endl;
feet = D.feet;
inches = D.inches;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main() {
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
They return void from the overloaded function. This makes sense to me if D1 is the object being called.
Other examples return a reference to a class object.
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
Distance& operator = (const Distance &D ) {
cout << "assigning..." << endl;
feet = D.feet;
inches = D.inches;
return *this;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main() {
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
This does not make sense to me (when taking the first example into consideration). If in the first example D1 = D2; invokes something like D1.=(D2);, why would the second example work in that case? Is it something like D1 = D1.=(D2);? And does it make any difference at the end of the day?
Although C++ language lets you overload assignment operator with any return type, including void, you should strongly consider following a widespread convention of returning a reference to the assignee from the operator.
The rationale for it is that
A = B;
will work no matter what the assignment returns, while
A = B = C;
which is a perfect chain of assignments will break, unless B = C returns something assignment-compatible to A (which is usually an object of the same type as A).
Another problem is in situations when you must compare the object as part of a larger expression, for example
mytype obj;
while ((obj = read_obj(cin)) != END_OBJ) {
...
}
Hence, the biggest drawback to returning void is inability to chain assignments and use them in places where void is not allowed.
As a convention, assignment operator usually returns reference (to *this); which makes it possible to chain the assignment, just like the behavior of those built-in types. e.g.
Distance D1, D2, D3;
D1 = D2 = D3;
For D1 = D2;, it's equivalent with D1.operator=(D2);. It doesn't change for the 2nd case, the returned value is just discarded. For D1 = D2 = D3;, it's equivalent with D1.operator=(D2.operator=(D3));. Note the returned value (i.e. reference to D2) is used as the argument for the assignment operator called on D1.

Changing what a pointer points to?

I am very new to programming, and am near the end of this program, but cannot quite finish the last detail, which I have been stuck on. I am attempting to switch what shape pointer *sp is pointing to, and it seems to me that what I am doing should work, since rectangle and circle both are shapes; however, when I compile, only the value of the color changes. The area of the circle prints instead of the area of the rectangle and the perimeter prints 0. Any help would be greatly appreciated!
#include <iostream>
#include <string>
using namespace std;
double const pi = 3.1519;
class shape {
public:
shape() {};
shape(string);
virtual double getCircumference() {
return 0;
};
virtual double getPerimeter() {
return 0;
};
virtual double getArea() {
return 0;
};
string getColor();
protected:
string color;
};
string shape::getColor() {
return color;
}
class circle : public shape {
public:
circle(double r, string c) {
radius = r;
color = c;
};
double getArea();
double getCircumference();
private:
double radius;
};
double circle::getCircumference() {
return pi * radius * 2;
}
double circle::getArea() {
return pi * radius * radius;
}
class rectangle:public shape {
public:
rectangle(double w, double l, string c) {
width = w;
length = l;
color = c;
};
double getArea();
double getPerimeter();
private:
double length;
double width;
};
double rectangle::getPerimeter() {
return width * 2 + length * 2;
}
double rectangle::getArea() {
return length * width;
}
void change(shape *sp, shape *sp1) {
*sp = *sp1;
}
int main() {
circle mary(3.2, "Green");
shape *sp = new circle(4.5, "Yellow");
cout << "Circle #1 is " << mary.getColor() << endl;
cout << "Circle #1 has an area of " << mary.getArea() << endl;
cout << "Circle #1 has a circumference of " << mary.getCircumference() << endl << endl;
cout << "Circle #2 is " << sp->getColor() << endl;
cout << "Circle #2 has an area of " << sp->getArea() << endl;
cout << "Circle #2 has a circumference of " << sp->getCircumference() << endl << endl;
shape *sp1 = new rectangle(1.0, 2.1, "Red");
change(sp, sp1);
cout << "Rectangle #1 is " << sp->getColor() << endl;
cout << "Rectangle #1 has an area of " << sp->getArea() << endl;
cout << "Rectangle #1 has a perimeter of " << sp->getPerimeter() <<endl<< endl;
}
It’s important to keep in mind what is meant by various different ways of using pointers. In your program, sp refers to the pointer itself—that is, a memory location telling the computer where to find an object. The asterisk in *sp is a ‘dereference’ operator; it takes a pointer and gives you the thing that it is pointing to.
With this in mind, your line *sp = *sp1; is saying, ‘take the thing that sp is pointing to, and set it to be equal to the thing that sp1 is pointing to.’ In other words, you are changing the value of the object pointed to by sp, not the value of sp itself. To point sp at the object pointed to by sp1, you need sp = sp1; with no asterisks.
The other thing to bear in mind is that C++ by default passes function arguments by value: when the function is called, the arguments are copied, and the function operates on the copies. This means that the original arguments themselves cannot be changed by a function that works like this. Adding an ampersand to the argument declaration, like void change(shape *&sp, shape *sp1) causes the first argument to be passed by reference: the object operated on by the function is the same object that was passed in by the calling code. This allows the function to change objects passed as arguments, and for those changes to remain after the function has returned.
Sorry for the long answer: I could have given you a few lines that did what you wanted, but I thought you might appreciate an explanation of the reason why things work the way they do.
If you are trying to change the address of pointers, you must pass pointers by reference. Try this:
void change(shape *&sp, shape *&sp1)
A pointer is passed by value even if it's a pointer.
This means that you are actually passing the address by value, so the argument is a copy of the original argument.
Think about
void sum(int a, int b, int result);
void foo() {
int result;
sum(5,10,result);
}
While you expect to be able to store the result into the variable passed to the sum argument you won't be able to do it since result is passed by value and hence copied. Every modification you do to result inside the method will be local to the method.
That's exactly the same thing, a pointer is nothing more than an address, if you pass it by value then a copy of the address is passed but every modification to the local variable is just local.
That's why you must use references if you want to be able to modify their values, exactly as every other variable, so you would have
void sum(int a, int b, int& result);
void change(shape*& shape1, shape*& shape2);
This, under the hood, will pass the address to the variable which stores the address (a sort of shape**) so the function is able to know where the original argument is located and modify it directly.

Conversion Fahrenheit to Celsius using class c

Hello everyone I'm having a problem. I'm fairly new and been stuck trying to solve it.
When I run it the first part where it prints 0 for the Fahrenheit to Celsius is correct but once I input a number it just prints the number I input. I know it probably a simple answer but thank you for your time.
#include <iostream>
using namespace std;
class Temp
{
public:
Temp(); //CONSTRUCTOR: Sets private variable for Fahrenheit to 32
void InputF(float F); //Initialize Fahrenheit temperature to F
void Celsius(); //PRINTS the Celsius temperature corresponding to
// the private Fahrenheit equivalent temperature
void ChangeBy(float D); //Changes the private Fahrenheit temperature
// by D degrees.
float Fahrenheit(); // returns the value of the private Fahrenheit temp
private:
float Fah; //Fahrenheit Temperature
};
int main() {
float FF;
Temp T; // Temperature Object
T.Celsius();
cout << endl; //Note that the value will be 0 since the private variable is 32.
cout << "Input a Fahrenheit temp: ";
cin >> FF;
T.InputF(FF);
cout << T.Fahrenheit() << endl;;
T.ChangeBy(34);
cout << T.Fahrenheit() << endl;
system("Pause");
return 0;
}
Temp::Temp() {
Fah = 32;
}
void Temp::InputF(float F) {
Fah = F;
}
void Temp::Celsius() {
cout << Fah;
}
void Temp::ChangeBy(float D) {
Fah = (5.0 / 9) * (Fah - 32);
}
float Temp::Fahrenheit() {
return Fah;
}
So, one issue:
void Temp::ChangeBy(float D)
{
Fah = (5.0/9)* (Fah - 32);
}
This method does not do what you say it does in the class declaration; your comment says that it updates Fah by the number of Fahrenheit degrees passed to it.
If I may suggest the following changes:
First, have ChangeBy simply add the input value to Fah:void Temp::ChangeBy( float D )
{
Fah += D;
}
Second, have the Celcius method do the conversion and return the converted value:float Temp::Celcius()
{
return (5.0/9.0) * (Fah - 32.0);
}
Finally, in your main function, write the output of Temp::Celcius() to the output stream:std::cout << T.Celcius() << std::endl;
EDIT
I took the liberty of rewriting your code to show what I mean; there isn't enough space in a single comment to really get the point across:
#include <iostream>
using namespace std;
class Temp
{
public:
Temp( float f = 32.0 ); // slight change here
void InputF(float F);
float Celsius() const; // note return type, addition of const
void ChangeBy(float D);
float Fahrenheit() const; // note addition of const
private:
float Fah;
};
int main() {
float FF;
Temp T;
cout << T.Celsius(); // Note that we output the result of Celsius in
// exactly the same manner that we do for
// Fahrenheit below.
cout << endl;
cout << "Input a Fahrenheit temp: ";
cin >> FF;
T.InputF(FF);
cout << T.Fahrenheit() << endl;
T.ChangeBy(34);
cout << T.Fahrenheit() << endl;
return 0;
}
/**
* Slight change here; we're using a member initializer, rather than
* assigning Fah in the body of the constructor. For a simple class
* like this it doesn't matter, but when you start getting into derived
* and virtual classes, using this method will make sure things get
* initialized in the right places and in the right order.
*/
Temp::Temp( float f ) : Fah(f) {
}
void Temp::InputF(float F) {
Fah = F;
}
float Temp::Celsius() const {
return (5.0f / 9.0f) * ( Fah - 32.0f ); // use f suffix for float constants
}
void Temp::ChangeBy(float D) {
Fah += D; // Update the value of Fah by the input value; the code you
// posted isn't using the value of D to update Fah, it was
// simply converting Fah to Celsius.
}
float Temp::Fahrenheit() const {
return Fah;
}
This code builds and runs on a Linux system using g++ with the -pedantic -Wall -Werror flags.
So, I've changed the return type of Celsius from void to float; instead of having Celsius print the value, it simply returns the value to main. This way Celsius doesn't have to worry about where the output gets written (what if you wanted to write to a file instead of cout, for example), and its focus is now much narrower.
I also changed the ChangeBy function; in the implementation you pasted above, you aren't actually using the input parameter D to change the value of Fah; you're simply converting the value of Fah from Fahrenheit to Celcius.
Notice that I also added the trailing const qualifier to the Fahrenheit and Celsius methods. This indicates that these two methods will not attempt to update any data internal to Temp. It's a good idea to make such "query" methods const in this manner; it keeps you from writing code that makes changes where it shouldn't.

error C2512: no appropriate default constructor available

I am getting this annoying error and I don't know why =( !
This is the question , I solved it but I am having a problem with the constructor.
Write a program that defines a class called Circle that includes radius (type double) as data members. Provide a set and a get function
for this data member. Ensure that the value entered by the user is
valid and correct (greater than zero).
Include function members: a.function member that compute and return Diameter of the circle b.function member that compute and
return Circumference of the circle c.function member that compute and
return Area of the circle d.function member that Display all
information of the circle e.constructor that initializes the data
member. If the radius is not valid (i.e. less than zero) set it to
zero.
the error I am facing :
error C2512: 'Circle' : no appropriate default constructor available
this is my code :
#include <iostream>
using namespace std;
class Circle
{
public:
Circle(double);
void setRadius(double);
double getRadius();
void Display();
double Diameter(double);
double Circumference(double);
double Area(double);
private:
double radius;
};
Circle::Circle(double radio)
{
setRadius(radio);
}
void Circle::setRadius(double ra)
{
if (ra < 0)
{
radius = 0;
}
else
radius = ra;
}
double Circle::getRadius()
{
double rado;
cout << "Enter the Radius:\n";
cin >> rado;
setRadius(rado);
return radius;
}
double Circle::Diameter(double rad)
{
return 2*rad;
}
double Circle::Area(double radi)
{
return 3.14 * radi * radi;
}
double Circle::Circumference(double radiu)
{
return 2 * 3.14 * radiu;
}
void Circle::Display()
{
cout << "The Radius of the circle is: \n";
cout << radius;
cout << "\nThe Diameter of the circle is: \n";
cout << Diameter(radius);
cout << "\nThe Circumference of the circle is: \n";
cout << Circumference(radius);
cout << "\nThe Area of the circle is: \n";
cout << Area(radius);
cout << endl;
}
int main()
{
Circle C;
C.getRadius();
C.Display();
return 0;
}
This line invokes a constructor with no arguments (known as default constructor):
Circle C;
The only constructor you have defined is:
Circle(double);
Hopefully this should point you in the right direction.
A default constructor is one without any parameters. Normally, it is provided for you. But if you explicitly define any other constructor, then it is not. So you have to define it yourself, or not use it. You are using it when you create an object in main, like this:
Circle C;
So, either define a default constructor, or don't use it.
Well, then add one :)
Circle() : radius(0.0) {}
You should define a constructor with no parameters called default constructor. You can initialize related members to the default values.
Circle::Circle()
{
radius = 0.0
}