Pragma, that is a terrible attitude to have. You remind me of the story of the college instructor who was teaching his class how to write a
linked list. When one of his students kindly remarked that his implementation leaked memory, he quickly stammered "Oh--well, no one worries about memory leaks, anymore..."
Of course, this is a total lie. People
do worry about memory leaks, even in an age of cheap memory.
A similar lesson lies here. If each class has a
constant table, there's no reason not to make it
static...
So, to that end, try something like this:
Code:
class dog
{
private: // it does no harm to explicitly declare access privilege...

 /*
 I don't know how well you know C++ but there are a few things to note.

 First, the const keyword modifies the thing to its _left_
 It's only a hack that, if there's nothing to its left, it modifies what's to its right.

 Second, private member functions can be _defined_ by child classes, they
 just can't be _called_ by child classes. See the distinction?

 Thirdly, the "= 0" modifyier, if you've never seen it before, means
 that the function has no definition. That means you can't actually make
 an instance of dog. You must make instances which define the "= 0" member
 function--typically the children...

 I hope this all makes sense to you! */
 int const * get_array_data() = 0;

public:
 void print_data();
};


class collie : public dog
{
private:
 static int const array[]; // there's no reason to make this public!

 int const * get_array_data()
 {
 return array;
 }
};

// keep your variables near the clases you define them in!
int const collie::array[2]={333,444};


class spaniel : public dog
{
private:
 static int const array[]; // there's no reason to make this public!

 int const * get_array_data()
 {
 return array;
 }
};

int const spaniel::array[2]={111,222};


void dog::print_data()
{
 int const * array = get_array_data();
 cout << array[0] << "\n";
 cout << array[1] << "\n";
}


On the surface, it looks like code is still duplicated, because a very similar get_array_data() must be implemented in each
child class. However, this really isn't the case. Each get_array_data() function honestly does something different. They return a very specific table, depending on the class, so its "re-implementation" cannot be avoided. However, you can guarantee it will never be any more complicated than what you see. You are still reusing the print_data() function from the
parent class, which may be very simple or very complicated, so all is well.
I'm tempted to say, from your question,
cliche, that you have a good intuition for writing maintainable code. Then again, you admitted you're not a beginner programmer so, perhaps, that's why...
Oh--and, please, be careful with your smileys!
...edited for clarity and correctness...