Can I cast an array like this? - c++

Example code:
#include <cstdlib>
#include <iostream>
using namespace std;
class A {
public:
A(int x, int y) : x(x), y(y) {}
int x, y;
};
class B {
public:
operator A() {
return A(x,y);
}
float x, y;
};
void func1(A a) {
cout << "(" << a.x << "," << a.y << ")" << endl;
}
void func2(A *a, int len) {
for(int i=0; i<len; ++i) {
cout << "(" << a->x << "," << a->y << ")";
}
cout << endl;
}
int main(int argc, char** argv) {
B b[10];
func1(b[0]);
//func2(b, 10);
return(EXIT_SUCCESS);
}
func1 works as expected, but func2 throws a compile-time error. Is there anything I can add to class B to make this work? I suspect not, but it doesn't hurt to ask, right?
I assume it won't work because the size of A is different from the size of B?

void func2(A *a, int len)
When you try to pass a pointer of type B to func2 there is no acceptable conversion from B* to A*. These are two different types from A and B, though the type B has a conversion operator to type A.

When you pass array to a method you are only passing the address of the first element not the actual copy of the array nor the first element.
In func1 you pass first element of array which is object of class B. Because B has operator A() it can convert B to A and new object of class A is passed to func1
In func2 you pass pointer to an array of B objects which is not the same as array of A objects so you get error.
To solve it you could have a transformation method that takes pointer to array of B's and iterators over it and for each calls func1 or something like that.

The other answers have addressed the core issue. But for completeness, it's worth noting that
I assume it won't work because the
size of A is different from the size
of B?
is incorrect.
First, A and B as given in this example would actually be the same size on many current compilers.
But even when A and B are the same size, the compiler will not perform this kind of conversion automatically. In fact, even if they have the exact same memory layout of member variables, the compiler will still not do it.

Related

Can't assign array element to class variable while overloading "=" operator

I am quite new in C++ programming, so maybe that's why I can't figure out why this assignment is not working.
In my class, I want to overload "=" operator.
I have specified a function, that outputs variables as an array. In overloading, I want to assign those variables to new object.
obj_new = obj_with_variables
overloading:
obj_new_x=obj_with_values_parameters()[0];
obj_new_y=obj_with_values_parameters()[1];
Here is a code:
// Test1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "string"
using namespace std;
class Vector2D
{
public:
Vector2D()
{
}
Vector2D(int& a, int& b)
:x(a), y(b)
{
}
void Drukuj()
{
cout << "wektor [" << x << ',' << y << "] \n";
}
void Wspolrzedne(int&a, int&b)
{
x = a;
y = b;
}
int* Wspolrzedne()
{
int tab[2] = { x,y };
return tab;
}
void operator = (Vector2D& obj)
{
int* a = obj.Wspolrzedne();
cout << a[0] << "\n";
x = a[0];
cout << x << " what? \n";
y = a[1];
}
private:
int x, y;
};
int main()
{
int x1 = 2, x2 = 3;
Vector2D wektor(x1, x2);
wektor.Drukuj();
Vector2D wektor2;
wektor2 = wektor;
wektor2.Drukuj();
wektor.Drukuj();
return 0;
}
The problem is that it assigns some strange values. However, if I don't use a reference, but declare 2 int values (j,k) and assign array element to them [0,1], it works fine.
Also, when using static numbers (for example, instead of a[0] ; use "2") it works fine too.
What is going on?
I would be glad if somebody could point me to right answer/ resources.
Regards,
In your member function int* Wspolrzedne(), you return the address of local variable tab. Accessing this variable once its life time has ended, as you do in your = operator, is undefined behaviour.
Your code has undefined behavior because operator= is accessing invalid data. Wspolrzedne() is returning a pointer to a local variable tab that goes out of scope when Wspolrzedne() exits, thus the a pointer used in operator= is not pointing at valid data.
If you want Wspolrzedne() to return multiple values, you need to have it return (by value) an instance of a struct or class to hold them. Try something more like this:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
struct Coordinate {
int x;
int y;
};
class Vector2D
{
public:
Vector2D()
: x(0), y(0)
{
}
Vector2D(int a, int b)
: x(a), y(b)
{
}
Vector2D(const Coordinate &c)
: x(c.x), y(c.y)
{
}
Vector2D(const Vector2D &src)
: x(src.x), y(src.y)
{
}
void Drukuj()
{
cout << "wektor [" << x << ',' << y << "] \n";
}
void Wspolrzedne(int a, int b)
{
x = a;
y = b;
}
void Wspolrzedne(const Coordinate &c)
{
x = c.x;
y = c.y;
}
Coordinate Wspolrzedne()
{
Coordinate c = { x, y };
return c;
}
Vector2D& operator=(const Vector2D &obj)
{
Coordinate c = obj.Wspolrzedne();
cout << c.x << ',' << c.y << "\n";
Wspolrzedne(c);
return *this;
}
private:
int x;
int y;
};
On the other hand, there is no real reason to even have operator= call Wspolrzedne() to get the coordinates at all, when it can just access obj.x and obj.y directly instead:
Vector2D& operator=(const Vector2D &obj)
{
x = obj.x;
y = obj.y;
return *this;
}
In which case, you can simply eliminate your operator= altogether, and let the compiler provide a default-generated implementation that does the exact same thing for you.
Your interface is dangerous, as returning raw pointers from functions means the caller must know how to manage it. That is, the caller needs to be astutely aware of the answers to questions like, "should the caller delete the pointer or does the object I got it from retain ownership?" What is this pointer pointing to? If it's an array, now many elements are there? If I must delete it, do I use delete or delete[]?
And so on. This is not good because it's very, very error prone.
Next you have a function that returns a pointer to stack-local data. When the function returns, that memory is already invalid so the return value is always going to result in undefined behavior to read.
int* Wspolrzedne()
{
int tab[2] = { x,y };
return tab; // BAD - returns pointer to function stack data
}
Where does tab live? It's destroyed when the function exits, but you're returning a pointer to it.
This is a dangerous interface and should be changed. Perhaps you should return the values as a pair:
std::pair<int, int> Wspolrzedne()
{
return std::pair{ x,y }; // assuming c++17
// return std::pair<int, int>{x, y}; // older compilers
}
An interface like this avoids pointers, and removes all the issues mentioned above.

Function returning unexpected struct values

I am completely new to structs and user defined datatypes, and i was trying to create a function that returns a struct:
The problem is highlight by the comment:
#include <iostream>
using namespace std;
struct num {
int n[2];
};
num func( num x, int a, int b) {
x.n[0] = a+b;
x.n[1] = a*b;
return x;
}
int main() {
int x,y;
num s1;
cout << "enter: ";
cin >> x >> y;
func(s1,x,y);
cout << s1.n[0] << "\n" << s1.n[1]; // THIS GIVES ERROR
cout << func(s1,x,y).n[0] << "\n" << func(s1,x,y).n[1]; // THIS DOENST GIVE ERROR
return 0;
}
I understand that second method makes sense and returns the struct variable. then putting a dot addresses the inner variable of struct.
But i dont understand why first method fails, or gives odd output. The function has done its job, ie made s1.n[0] = x + y and s1.n[1] = x*y
Now, printing s1.n[0] should print x + y only. How can we check and correct the internal workings of the function?
You have to assign the returned value to the structure object in main
s1 = func(s1,x,y);
Inside the body the function deals with a copy of the original object. It does not change the original object because it is passed by value.
Another approach is to pass the structure by reference
void func( num &x, int a, int b) {
x.n[0] = a+b;
x.n[1] = a*b;
}
In this case in main you could just write
func(s1,x,y);
Or you could use even so-called C approach of passing by reference
void func( num *x, int a, int b) {
x->n[0] = a+b;
x->n[1] = a*b;
}
and call it like
func( &s1, x, y );
As for this statement
cout << func(s1,x,y).n[0] << "\n" << func(s1,x,y).n[1];
then you access data members of two temporary objects returned by the two calls of the function. After executing this statement these temporary objects will be deleted.
It looks like you are never assigning the return value of func(). Your function returns the struct, but you are never assigning it. To fix this, you should be able to simply say: s1 = func(s1,x,y); This will assign the modified version of the struct to the s1 variable.
Alternatively, you could rewrite func() to accept a pointer to the struct. This would allow you to modify the struct without having to return it:
void func( num *x, int a, int b) {
x->n[0] = a+b;
x->n[1] = a*b;
}
Then you would just change your call to func() to say: func(&s1, x, y);
You are not passing your struct by reference, hence the result. Try the following:
void func(num &x, int a, int b) {
x.n[0] = a+b;
x.n[1] = a*b;
}
There's no need for the function to return anything since your struct is passed by reference and it will be changed anyway. Void would fit better.
This is because you have passed the struct by value while your intentions look like you want to pass by reference.
Check this link : http://courses.washington.edu/css342/zander/css332/passby.html
num func( num &x, int a, int b)
should fix your problem

swap with non-const reference parameters

I got [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
#include <stdio.h>
void swap(float &a, float &b){
float temp=a;
a=b;
b=temp;
}
main()
{
int a=10, b=5;
swap((float)a, (float)b);
printf("%d%d",a,b);
}
Vlad is correct, why cast to float? Use int for all values. However, if you have some reason for doing it that way, you must be consistent in your cast and references:
#include <stdio.h>
void swap(float *a, float *b){
float temp=*a;
*a=*b;
*b=temp;
}
int main()
{
int a=10, b=5;
swap((float*)&a, (float*)&b);
printf("\n%d%d\n\n",a,b);
return 0;
}
output:
$ ./bin/floatcast
510
When you pass an address to a function, it must take a pointer as an argument. Thus void swap(float *a,.. When you need a reference to an address of a variable (to pass as a pointer), you use the address of operator &. When you handle values passed as a pointer, in order to operate on the values pointed to by the pointer you must dereference the pointer using the * operator. Putting all that together, you get your code above. (much easier to just use int... :)
C++ Refernce
If I understand what you want in your comment, you want something like this:
#include <iostream>
// using namespace std;
void swap(float& a, float& b){
float temp=a;
a=b;
b=temp;
}
int main()
{
int a=10, b=5;
swap ((float&)a, (float&)b);
std::cout << std::endl << a << b << std::endl << std::endl;
return 0;
}
output:
$ ./bin/floatref
510
You are trying to swap temporary objects (created due to using the casting). that moreover would be deleted after exiting from the swap. You may not bind temporary objects with non-constant references. So there is no sense in such a call. It is entire unclear why you are trying to cast the both integers to float that to swap them. Why do not swap integers themselves?
Write the function like
void swap( int &a, int &b )
{
int temp = a;
a = b;
b = temp;
}
Take into account that there is already standard function std::swap
If you want to write swap function in C then it will look like
void swap( int *a, int *b )
{
int temp = *a;
*a = *b;
*b = temp;
}
You have to get the array using the pointers(*). While passing only you have to give the ampersand(&). Use this following code.
#include <stdio.h>
void swap(int* a, int *b){
float temp=*a;
*a=*b;
*b=temp;
}
main()
{
int a=10, b=5;
swap(&a, &b);
printf("%d \t %d\n",a,b);
}
In C++ you should be using std::swap, or if you prefer you can write your own template that will swap any two values.
template <typename T>
void swap(T & a, T & b)
{
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 10, b = 5;
swap(a, b);
std::cout << a << " \t " << b << std::endl;
return 0;
}
What you are trying to accomplish (treating an int as a float) is going to result in undefined behavior -- it might work on your compiler but it could easily break on a different compiler or architecture. You can use reinterpret_cast to force this behavior if you really want to.

Calling Class Constructor in Member Function

Here's a program, where I am trying to call the class constructor multi::multi(int, int), in the function void multi::multiply(). The output is
30
30
instead of expected
30
25
Why?
#include <iostream.h>
class multi{
private:
int a;
int b;
public:
multi(int m, int n){
a = m;
b = n;
}
void multiply(){
cout << "\n\n" << a*b;
multi (5, 5);
cout << "\n" << a*b;
}
};
main(){
multi x(5,6);
x.multiply();
return 0;
}
multi (5, 5);
It creates a temporary object, and gets destroyed by the end of the full expression. It doesn't do multiplication or printing.
To see the desired output, you can add a reset() member function to your class:
class multi{
private:
int a;
int b;
public:
multi(int m, int n) : a(m), b(n) {} //rewrote it
void reset(int m, int n) { a = m; b = n; } //added by me
void multiply(){
cout << "\n\n" << a*b;
reset(5, 5); //<-------------- note this
cout << "\n" << a*b;
}
};
By the way, prefer using member-initialization-list when defining constructors.
When you're calling the constructor multi(5, 5) you're actually creating a temporary object that is immediately destructed.
This doesn't work, because multi(5, 5); creates a temporary object of class multi, which is immediately destroyed, because it is not used for anything
Since multiply() is a member function of class multi, it has access to the private members, so it can just set a and b directly. You can get your expected output by rewriting multiply like this:
void multiply()
{
cout << "\n\n" << a*b;
b = 5;
cout << "\n" << a*b;
}
You can't call constructors like this. What your code does is create a new temporary instance of multi, which gets discarded immediately.
Once an object is constructed, you can't call its constructor again. Create an assign() function or something similar in your class.
You can't call a constructor of an already created object. What you are doing in code is, creating a temporary object.
Compiler will report error if you do try to do
this->multi(5,5).

Syntax for Accessing Dereferenced Values of an Object

In the following code:
#include <iostream>
class Foo{
public:
int *a, *b;
}
Foo::Foo(int x, int y) : a( new int ( x ) ) , b( new int ( y ) )
{
}
Foo test(1,2);
If I want to cout the derefereced value stored in pointer variable a, why do I write:
std::cout << *test.a << std::endl; //method 1
and not:
std::cout << test.(*a) << std::endl; //method 2
It would seem to me that we are accessing the dereferenced value of a i.e. *a, and this is a member variable of the test object of class Foo so method 2 feels more syntactically correct. Method 1 (the correct way I believe) appears to dereference the whole test object.
The reason you need *test.a instead of test.(*a) is because a itself does't exist (from a variable in scope perspective). It's a member of Foo so to access Foo::a you need test.a. Then you apply * to test.a since test.a is a pointer.