1

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;
        }
    }
};
5
  • Why are you shadowing your parent's definition of array? Commented Jun 23, 2014 at 15:58
  • 2
    i want to new an array Don't. Pretty please with a dollop of ice cream and a cherry on top don't. Arrays are bad for you. Arrays cause plaque in your teeth and early onset of Alzheimer's. new is responsible for global warming and vegan zombie apocalypsis due any day now. Use std::vector, a healthy, environment-friendly, GMO-free choice of the no-new generation. Commented Jun 23, 2014 at 16:14
  • 1
    Turn up your warning level. Commented Jun 23, 2014 at 16:21
  • @n.m. such a funny comment!! :))) i use vector a lot! but this time i like to know how it works! :D Commented Jun 23, 2014 at 16:41
  • @chris: thanks! i try it next time! i completely forgot to check warnings before asking question. thanks!! :))) Commented Jun 23, 2014 at 16:42

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks!! it's so good. but i have an another question. what is the purpose of setting objects after constructor and not set them in the constructor scope? what are advantages of this way? (except calling the parent constructor!) thanks a lot again for your answer
@AlimohammdForoutannezhad It is a good idea to set all objects in the constructor, either through the initializer list (when possible) or through code in the body of the constructor itself. Sometimes it is not possible to set member variables in the initializer list, for example, because the values need extensive computation which is based on the call to the constructor of the base class. That's when you use the body of the constructor instead of the initializer list.
thanks a lot again. it was so helpful and useful. :))
3

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.

Comments

0

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.

Comments

0

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.

1 Comment

it is such a geeky way. but there is a problem. i want to init the child from parent. but you init the child inside itself!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.