Some trouble with derived classes [duplicate] - c++

This question already has answers here:
Assigning derived class array to base class pointer
(3 answers)
Closed 8 years ago.
I am trying to implement the functions and classes below, but the output for arr[i].x is wrong. I correctly get arr[0].x = 0 and arr[1].x = 0, but arr[2].x does not return 0. Any ideas why?
class Base {
public:
int x;
};
class Derived : public Base {
public:
int y;
void init(Base *b);
void foo();
};
void Derived :: init(Base *b) {
for( int i = 0; i < 3; ++i) {
b[i].x = 0;
}
}
void Derived :: foo() {
Derived arr[3];
init(arr);
for( int i = 0; i < 3; ++i) {
cout<<"b["<<i<<"] "<<arr[i].x;
}
}
int main()
{
Derived der;
der.foo();
return 0;
}

void Derived :: foo() {
Derived arr[3];
init(arr);
a pointer to Derived, Derived*, is passed to function init(Base *b). What happens next is that instead of moving by the sizeof(Derived)=8 in the table your function will move by sizeof(Base)=4 what results in initialization of x member for first and second Derived in array and for y of first Derived, but not for x of last Derived.
Pointer arithmetic is done based on the size of the type of the
pointer
Consider this memory layout (on x64):
in Derived::foo():
Derived arr[3];
0x7fffffffe310 // 1st Derived, also address of arr[0].x
+8 =
0x7fffffffe318 // 2nd Derived, also address of arr[1].x
+8 =
0x7fffffffe320 // 3rd Derived, also address of arr[2].x
but in Derived::init( Base* b):
b[0].x = 0x7fffffffe310 // set arr[0].x to 0
+4 =
b[1].x = 0x7fffffffe314 // set arr[0].y to 0
+4 =
b[2].x = 0x7fffffffe318 // set arr[1].x to 0
Thus, you have set arr[0].x to 0, arr[1].x to 0 and incidentally arr[0].y to 0. This is not what you want. Solution is to change Derived::init to
void Derived::init( Derived *d) {
for( int i = 0; i < 3; ++i) {
d[i].x = 0;
}
}
or even better, following principle of more generic programming:
template < size_t N>
void Derived::init( Derived (&d)[N] ) {
for( int i = 0; i < N; ++i) {
d[i].x = 0;
}
}

The reason is that init() has no idea that you are really passing a Derived* instead of a Base*.
So the loop in the init() function, the assumption is made that to get to the next entry in the array, sizeof(Base) is added to the pointer, not sizeof(Derived).

change
cout<<"b["<<i<<"] "<<arr[i].x;
to
cout<<"b["<<i<<"] "<<arr[i].x<<endl;
Then you will see the correct number.
The extra function of endl is to flush the buffer associated with this stream. if you don't do that, it will output some random number sometimes.

For one you're passing the pointer (*b) to the function init() by value, not by reference.
Here's a nice explanation as to why that matters They explain it better than I likely could
Try making the function init look like this
init(Base& *b)
See what happens.

Related

How to pass object array to a function?

class department
{
void max() ***HOW TO PASS ARRAY OF OBJECT HERE , WHAT PARAMETERS SHOULD I PASS***
{
}
};
class B : public department {
};
int main()
{
B a[10];
// a.max(a,n); ***HOW TO CALL THIS max FUNCTION***
return 0;
}
I want to pass the array of object a[10] to the max function. How do I call it and pass it?
I don't want to do it like this:
for(i = 0; i < n; i++)
{
a[i].max
}
You implemented max() as a non-static method of department, so you need a department object to call it on, like each B object in your array, eg:
for(int i = 0; i < 10; ++i)
{
a[i].max();
}
If this is not what you want, then max() needs to be taken out of department, or at least made to be static instead. Either way, you will have to change its input parameters to accept the array.
Try something more like this instead:
class department
{
public:
static void max(department *depts, int count)
{
//...
}
};
class B : public department {
};
int main()
{
B a[10];
department::max(a, 10);
return 0;
}
Online Demo
Alternatively:
class department {
};
class B : public department {
};
void max(department *depts, int count)
{
//...
}
int main()
{
B a[10];
max(a, 10);
return 0;
}
Online Demo
How to pass object array to a function?
The parameter of a function cannot be an array in C++. A parameter can be a reference to an array. Alternatively, it is common to pass iterator pointing to an element of an array. Object pointer is an iterator for an array.
department::max() is a non-static member function. It has empty parameter list, so it accepts no arguments at all, except for the implicit class instance that is used as the left hand operand of a member access operator. Since this function accepts no reference to array parameter nor a pointer parameter, there's no way to pass an array as an argument.
Here is an example of a function that does accept a reference to an array as a parameter, and of how to call such function:
void max(B (&arr)[10]);
int main()
{
B a[10];
max(a);
}

Pointer to array Maintain counter of elements

I have an interface which multiple classes inheritance.
class someInterface
{
virtual void someMethod() = 0;
}
class A : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class B : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class C : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
For each of the classes A, B, C i have created an array with different sizes of their actual type inside a container class.
class AContainer
{
public:
A As[10];
}
class BContainer
{
public:
B Bs[5];
}
etc...
Furthermore i have an array of pointers to "SomeInterface", where i want to have a pointer to each of the actual arrays like this.
#define SOMEINTERRFACE_SIZE 3
someInterface *array[SOMEINTERRFACE_SIZE];
array[0] = AContainer.As; //Could also just be &AContainer.As[0]
array[1] = BContainer.Bs;
array[2] = CContainer.Cs;
for (int i = 0; i < SOMEINTERRFACE_SIZE; ++i)
{
int elements = //Here i need a solution to get the size
//So i can iterate through the array, which the pointer points to.
for (int i = 0; i < elements; ++i)
{
//Call the interface method on each element.
}
}
The problem occurs, when i have to use the someInterface array, since it isn't possible to get the size of the actual array through the someInterface pointer..
What is a good solution to this problem? I really need some help to solve this.
Also don't want to use dynamic allocation, so no solution with vector<> or malloc etc. because I'm writing to an Arduino.
It won't work. In C++ you have to know the size of the elements in an array. A, B, and C might be different sizes, so you can't treat arrays of them the same.
&AContainer.As[i] == &AContainer.As + i * sizeof(A)
but
&BContainer.Bs[i] == &BContainer.Bs + i * sizeof(B)
So it's impossible for the same machine code to iterate over arrays of A and of B. If you want to iterate over an array of objects, you need to know the exact type.
Remember in C++, if you want to get a polymorphic virtual call, you need to go through pointer or reference. The solution is to copy pointers to the elements in each array into one "master" array.
SomeInterface *ptrs[NUM_A + NUM_B + NUM_C];
SomeInterface **dest = ptrs;
for (int i = 0; i < NUM_A; ++i) {
*dest++ = &AContainer.As[i];
}
for (int i = 0; i < NUM_B; ++i) {
*dest++ = &BContainer.Bs[i];
}
// et cetera...
This only uses a little bit of extra space because you're storing pointers, not actual objects.
EDIT: I guess you could do something like this if you really want to save the space:
someInterface *arrays[] = { AContainer.As, BContainer.Bs, CContainer.Cs };
int objSizes[] = { sizeof(A), sizeof(B), sizeof(C) };
int arrLengths[] = { NUM_A, NUM_B, NUM_C };
for (int j = 0; j < sizeof(arrays)/sizeof(arrays[0]); ++j)
{
void *ptr = arrays[j];
for (int i = 0; i < arrLengths[j]; ++i) {
someInterface *iptr = (someInterface *)ptr;
iptr->method();
ptr += objSizes[j];
}
}
(this is untested, you might need to tweak a little.)
In theory since all those arrays are full of compile-time constants, it should optimize out to something fast. If it doesn't, the code will run slower because it will be incrementing pointers by a value only known at runtime instead of compile time. You should check the assembly output if you really care about speed.
Difficult to answer without knowing more details of your application - but here a a few ideas that might help.
Given:
class someInterface { public: virtual char someMethod() = 0; };
class A : public someInterface { public: char someMethod() { return 'A'; } };
class B : public someInterface { public: char someMethod() { return 'B'; } };
class C : public someInterface { public: char someMethod() { return 'C'; } };
You could hand-roll something like this:
class Array {
public:
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < countA ; ++i) function(As[i]);
for (size_t i = 0 ; i < countB ; ++i) function(Bs[i]);
for (size_t i = 0 ; i < countC ; ++i) function(Cs[i]);
}
private:
enum {countA = 10, countB = 5, countC = 3};
A As[countA];
B Bs[countB];
C Cs[countC];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array array;
array.forEach(doSomeMethod);
return 0;
}
Note that by using the "callback" function doSomeMethod, we get around a typical problem of dispatching in polymorphic collections.
Of course, you don't want to keep hand-rolling things like that. Fortuanately the Arduino C++ compiler I checked out has template support, so you could do something like:
template <class T, size_t _size, class NextArray = void>
struct Array {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
nextArray.forEach(function);
}
private:
T elements[_size];
NextArray nextArray;
};
template <class T, size_t _size>
struct Array<T, _size, void> {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
}
private:
T elements[_size];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array<A, 10, Array<B, 5, Array<C, 3> > > array;
array.forEach(doSomeMethod);
return 0;
}
Which gets the compiler to write it for you for different combinations of types and sizes. A few things worth noting:
All the magic is done at compile time. Check out the assembly generated by an optimising compiler to see how small and fast this can be.
Read up on c++ "functors" if your callback function needs some state.
If your compiler supports variadic templates and/or lambdas, this becomes simpler (I'm assuming the Arduido compiler doesn't yet)
If you can't use the callback approach (and your compiler doesn't support lambdas yet), then you could try this next option, which incurs some small run-time cost over the option given above:
template <class Interface>
class ArrayInterface {
public:
virtual size_t getSize() = 0;
virtual Interface& getElement(size_t index) = 0;
};
template <class T, class Interface, size_t size>
class Array : public ArrayInterface<Interface> {
public:
size_t getSize() { return size; }
Interface& getElement(size_t index) { return element[index]; }
private:
T element[size];
};
int main(int, char**) {
Array<A, SomeInterface, 10> As;
Array<B, SomeInterface, 5> Bs;
Array<C, SomeInterface, 3> Cs;
const int SOMEINTERRFACE_SIZE = 3;
ArrayInterface<SomeInterface>* array[SOMEINTERRFACE_SIZE] = {&As, &Bs, &Cs};
for (size_t i = 0 ; i < SOMEINTERRFACE_SIZE ; ++i) {
ArrayInterface<SomeInterface>& innerArray = *array[i];
for (size_t j = 0 ; j < innerArray.getSize() ; ++j)
std::cout << innerArray.getElement(j).someMethod();
}
return 0;
}
(This last one uses an outer array of pointers, as per your question)
This post is already too long, so I haven't gone into much detail, or delved into options such as a single, flat array of member function pointers. If you have any questions, just shout.
Is it what you are trying to achive?
Iterate over a list of objects and call a reimplemented method of a common interface?
Put this piece of code anywhere in global C++ scope for testing.
#include <vector>
#include <iostream>
int TestSomewhereInCppGlobalScopeCode()
{
class someInterface
{
public:
virtual void someMethod() = 0;
};
class A : public someInterface
{
public:
void someMethod()
{
std::cout << "A::someMethod()";
}
};
class B : public someInterface
{
public:
void someMethod()
{
std::cout << "B::someMethod()";
}
};
class C : public someInterface
{
public:
void someMethod()
{
std::cout << "C::someMethod()";
}
};
std::vector<someInterface*> ListOfObjectsHavingCommonInterface;
ListOfObjectsHavingCommonInterface.push_back( new A );
ListOfObjectsHavingCommonInterface.push_back( new B );
ListOfObjectsHavingCommonInterface.push_back( new C );
for ( std::vector<someInterface*>::iterator it = ListOfObjectsHavingCommonInterface.begin();
it != ListOfObjectsHavingCommonInterface.end();
++it )
{
(*it)->someMethod();
}
return 0;
}
static int TestSomewhereInCppGlobalScopeCode_Caller = TestSomewhereInCppGlobalScopeCode();

Initializing a vector on a class constructor

I'm doing this A class which has a vector of B's. I'm initializing the vector on the constructor of the A class (I'm not sure if this is the right way, but it compiles). Besides this, I'm having a problem because I don't want that when initializing the vector that it initializes himself with the default construtor of B() because this makes me do a for loop to set the value that I want. It would be fine if the vector position stood NULL or stood 0 to size;
class B{
int _t;
public:
B(){ _t = 1; }
B(int t) : _t(t){}
};
class A{
std::vector<B> _b;
public:
A(int size): _b(size){
for(int i = 0; i < size; i++){
_b[i].setNumber(i);
}
};
int main() {
int n = 3;
A _a(n);
return 0;
}
You can simply let the vector be default constructed (empty), then emplace_back into it:
A(int size) {
_b.reserve(size);
for(int i = 0; i < size; i++){
_b.emplace_back(i);
}
}
If you are stuck with a pre-C++11 compiler, you can push_back B objects into it:
A(int size) {
_b.reserve(size);
for(int i = 0; i < size; i++){
_b.push_back(B(i));
}
}
The calls to std::vector::reserve are to avoid re-allocations as the vector grows in size.
It does not compile. class B does not have a setNumber function. Initializing the vector to a size does not require you to do anything. It would just default construct number of objects equal to the specified size. Vector has a reserve member function that allows you to allocate enough memory for some number of elements without actually constructing objects. Perhaps that is what you were seeking. Obviously leaving it empty until you are ready to perform some form of insertion is another option. Hopefully one or more of the posted answers will help.
class A{
std::vector<B> _b;
public:
A(int size){
_b.reserve(size);
}
};

C++ how to pass array of pointers to a function

I need to pass an array of pointers to a function,
In the example below, there is a class called base and an array of pointers called pool.
How can I pass the array pool to a function called function?
1) in case that I want to be able to change the original array of pointers.
2) in case that I only want to pass a copy of the array of pointers.
Thanks,
class base
{
};
void function (base * pool)
{
}
int main
{
base *pool[40];
function (pool[0]);
return 0;
}
class base
{
public:
int a;
};
void function (base ** pool)
{
for (int i = 0 ; i < 40; ++i)
cout<<pool[i]->a<<' ';
}
int main()
{
base *pool[40];
// Allocate 40 base objects and the 40 base pointers
// point to them respectively
for(int i = 0; i < 40; ++i)
{
pool[i] = new base;
pool[i]->a = i;
}
function (pool);
// free the 40 objects
for(int i = 0; i < 40; ++i)
delete pool[i];
return 0;
}
I added the a member just as an example.
Even better would be
void function (base ** pool, int n)
{
for (int i = 0 ; i < n; ++i)
cout<<pool[i]->a<<' ';
}
and
function (pool, n);
It's not so easy to pass a copy of the array - especially in the case where the objects itself are dynamically allocated.
To pass an array to a function, and maintain the type information about the array, you can use a template:
template <unsigned N>
void function (base *(&pool)[N]) {
}
There is no way to pass a copy of an array, unless it is inside a struct or class. In C++11, you have such a class in STL, called array:
#include <array>
template <unsigned N>
void function (std::array<base *, N> pool) {
pool[0] = 0;
}
base b;
std::array<base *, 40> p;
p[0] = &b;
function(p);
assert(p[0] == &b);

Pointer to object arrays as members overwrite memory

Here is the deal. We have 2 different classes Class F and Class O
class F {
private:
int x;
int y;
public:
int getXf(){ return x; }
int getYf(){ return y; }
f(int ,int);
};
class O {
private:
int n;
int k;
int x;
int y;
char type;
int id;
int t;
public:
O(int ,int ,int ,int ,int);
int getX(){ return x; }
int getY(){ return y; }
};
And we have a third class P, where we initialize the values. In the class we are creating the two arrays of objects.
class Prog {
public:
int count;
int fcount;
O *o[]; //here we are declaring the arrays of objects
F *f[];
public :
//void init(); Here is the function where we initializing the values
};
Now the 2 for statements where we are creating the objects.
for(int i=0;i<10;i++){
randx = rand() % 10;
randy = rand() % 20;
o[i] = new O(100,50,i,randx,randy);
}
for(int i=0;i<3;i++){
randx = rand() % 10;
randy = rand() % 10;
f[i] = new F(randx, randy);
}
When we are printing all of the objects are here but the first 3 of the first class are replaced by the objects of the seconds. Exactly the 100 and 50 (1st for) from randx and randy (2nd for) respectively.
O *o[];
This declares an array of unknown size, which is an incomplete type. C++ doesn't allow that to be used as a class member, although some compilers will allow it as an extension, interpreting it as an array of zero size. In either case, it's not what you want.
If you know the array bound at compile time, then you should specify it:
O *o[10];
otherwise, you'll need to dynamically allocate an array at run time:
std::vector<O*> o;
for(int i=0;i<10;i++){
randx = rand() % 10;
randy = rand() % 20;
o.push_back(new O(100,50,i,randx,randy));
}
I would also suggest storing objects, or possibly smart pointers, rather than raw pointers in the array. If you really do want raw pointers for some reason, then remember to delete the objects once you've finished with them since that won't happen automatically, and don't forget the Rule of Three.
You are declaring arrays, but you never allocate memory for them. What you are seeing is just how your code is walking all over the stack.
Something more appropriate:
struct X {}; struct Y {};
class P {
public:
P() : xs(new X*[10]), ys(new Y*[10]) { init(); }
~P() {
// delete all objects
for(std::size_t i = 0; i < 10; ++i)
delete xs[i];
for(std::size_t i = 0; i < 10; ++i)
delete ys[i];
delete[] xs;
delete[] ys;
}
private:
void init() {
// initialize
for(std::size_t i = 0; i < 10; ++i)
xs[i] = new X();
for(std::size_t i = 0; i < 10; ++i)
ys[i] = new Y();
}
// prevent assignment and copy
P& operator=(const P& other);
P(const P&);
X** xs;
Y** ys;
};
Of course, all this magic becomes unnecessary if you just use
std::vector to store your data.
The problem is due to the way you declare your arrays:
O *o[/*No size here*/];
F *f[/*No size here*/];
Since you do not state the size of the arrays, this is equivalent to
O **o;
F **f;
Hence, you are declaring two members of types "pointer to pointer to O" and "pointer to pointer to F" respectively, but these are uninitialized and you have not allocated any memory for them to point to. That is, you actually don't have any arrays, just pointers which could be used to refer to the type of array you want.
If you know at compile time what size you want to use, you should specify that size in the declaration, which will give you a properly allocated array of that size. Otherwise, consider using an std::vector.