Your inheritance setup is fine. However, you have a problem with your member variable x2: it is never dimensioned. I think you're attempting to dimension is with the line "this->x2[this->x1]" but that is incorrect, that is interpreted as "read x2[x1]", where x1 = 2, therefore it'll run as "read x2[2]", which will do nothing since you're not even assigning the result, so the compiler would likely optimize it away.
Something you need to know about C/C++ is that it doesn't really "do" arrays in the same way that other languages do, they're essentially just syntactic sugar around pointers, which means you can't dynamically resize arrays at runtime in the way you're attempting to do so. They also don't do bounds-checking. Consequently, x2 is never being properly initialized: No memory is being allocated for the contents of the array, and the x2 pointer itself is also undefined. So, when you subsequently assign to members of this array (writing zeroes to it in the constructor, and then doing that addition to it in loop) you're not actually writing to x2, because x2 doesn't exist. You're writing to some arbitrary other piece of memory, which could literally be anything. This is likely the source of your problems.
You need to dimensiont the array in the place where its declared, which is in SubClass.h on line 13: "x2[]," should read "x2[2],". Note you can't use x1 here because x1 is a runtime non-constant variable, so you'd need to make a constant or a macro to store this information if they're related, e.g...
class SubClass : public SuperClass {
public:
SubClass();
~SubClass();
const int ARRAY_SIZE = 2;
int x1 = ARRAY_SIZE,
x2[ARRAY_SIZE],
x3;
virtual void loop();
void f1(int i1);
};
If in future you actually want to be able to dynamically resize arrays, you do that by creating and deleting memory to the pointer:
const int size1 = 5; //Size of the array I want.
const int size2 = 10;
int* foo; //Declaration. No memory assigned. Accesses will be undefined.
foo[2] = 56; //WRONG.
foo[7] = 56; //WRONG.
foo = new int[size1]; //OK, now foo points to a valid array with five members.
foo[2] = 56; //Good!
foo[7] = 56; //WRONG.
delete[] foo; //We've deallocated the foo array, so now accesses will be undefined.
foo[2] = 56; //WRONG.
foo[7] = 56; //WRONG.
foo = new int[size2]; //OK, now foo points to a valid array with ten members.
foo[2] = 56; //Good!
foo[7] = 56; //Good!
delete[] foo; //We've deallocated the foo array, so now accesses will be undefined.
Note the use of delete[] is very important otherwise you'll introduce memory leaks because you'll be allocating memory but never deallocating it. When you get into dynamic memory allocation in C++, YOU the programmer are responsible for managing it, neither the runtime environment nor the compiler will help you.
I hope all that helps and is not an information overload!