strings95
strings95

Reputation: 681

Passing array pointer from derived class to base class C++

I'm trying to understand inheritance in C++.

I want to dynamically create an array in a derived class and pass the array pointer to the base class, and then the base class fills in the array. Finally I want to print the array from the derived class.

I wrote the following code but when I run this, the program crashes and I get a segmentation fault error.

How should I implement this?!

class Base {
private:
    int* array;
public:
    Base(int* a) {
        array = a;
        for(int i = 0 ; i < 10 ; i++) {
            array[i] = i;
        }
    }
};

class Child : public Base {
private:
    int* array;
public:
    Child() : array(new int[10]), Base(array) {}
    void print() {
        for(int i = 0 ; i < 10 ; i++) {
            cout << array[i] << endl;
        }
    }
};

Upvotes: 1

Views: 1395

Answers (4)

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42909

One solution would be to use std::array instead of raw pointer like the example below:

#include <iostream>
#include <array>

template<typename T, std::size_t N>
class Base
{
private:
    std::array<T, N> const &array;
public:
    Base(std::array<T, N> const &a) : array(a) { }
    void print() const {
      std::cout << "Printing array from Base class!" << std::endl;
      for(auto i : array) std::cout << i << " ";
      std::cout << std::endl;
    }
};

template<typename T, std::size_t N>
class Child : public Base<T, N> {
private :
  std::array<T, N> array;
public:
  Child() : Base<T, N>(array) { 
    for(auto &i : array) i = 10;
  }

  void print() {
    std::cout << "Printing array from Child class!" << std::endl;
    for(auto i : array) std::cout << i << " ";
    std::cout << std::endl;
  }
};

auto main() -> int {
  Child<int, 10> c;
  c.print();
  Base<int, 10> *b = &c;
  b->print();

  return 0;
}

Live Demo


Thus:

  • You wouldn't have to worry about releasing previously allocated memory.

  • Your Base class keeps a constant reference to the array object of the Child class. Thus, you save memory.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726639

The problem here is that the order of items in the initializer list does not influence the order in which the initialization is actually performed; only the order in which the members are declared is considered. Moreover, the initialization of the base always happens first.

Therefore, the Child constructor is actually executed as follows:

  • Base(array) is invoked (array is not set here!)
  • array is assigned a valid value.

Fortunately, all you need to do to fix this problem is to remove the array from the Child: it is redundant anyway:

class Child : public Base {
public:

    Child() : Base(new int[10]) {
    }

    void print() {
        for(int i = 0 ; i < 10 ; i++) {
            // Make a[] protected in the parent
            cout << a[i] << endl;
        }
    }
};

class Base
{
protected:
    int *array;
...
}

If you would rather not make a protected in the parent, you can fix your code as follows (demo):

Child() : Base(array = new int[10]) {}

This is suboptimal, though, because a redundant member is kept in all instances of Child.

Upvotes: 5

Mike Seymour
Mike Seymour

Reputation: 254471

Base subobjects are initialised before class members, even if you write the initialisers in another order. So here:

Child(): array(new int[10]), Base(array)

the Base object is initialised first, using the uninitialised value of array.

Solutions include:

  • make Base::array accessible from Child, so it doesn't need its own copy;
  • move print into the base class, so that Child doesn't need to access array;
  • do something nasty like Child() : Base(array = new int[10]), if you really need a redundant copy of an inaccessible variable for some reason.

Make sure you've enabled compiler warnings; they should have caught this error.

Upvotes: 3

Christophe
Christophe

Reputation: 73386

It's because the base object is constructed first, and only then the child is constructed.

This means that your array is unintialised.

Put some tracing message at the begin and end of each of your consutructors, and you'll get a better understanding of how things work.

Upvotes: 0

Related Questions