5

I have 2 classes, A and B. In A I have 3 private fields. In class B I would like to write a copy constructor, and initialize private fields from class A. However, this does not work:

#include <iostream>
#include <string>
using namespace std;

class A
{
    private:

        string *field1;
        string *field2;
        string *field3;
        double num1;

    public:

        A(string *o, string *n, string *m, double a=0)
        {
            field1 = new string(*o);
            field2 = new string(*n);
            field3 = new string(*m);
            num1 = a;
        }

        A(const A& other) {
            field1 = new string(*other.field1);
            field2 = new string(*other.field2);
            field3 = new string(*other.field3);
            num1 = other.num1;
        }

        void show()
        {
            cout << *field1 << " " << *field2 << " " << *field3 << "\n";
        }

        ~A()
        {
            delete field1;
            delete field2;
            delete field3;
        }
};

/*--------------------------------------------------------------------------------------------*/

class B : public A
{
    private :

        double num2;
        double num3;

    public:

        B(double num2, double num3, string *o, string *n, string *num, double a=0) : A(o,n,num,a)
        {
            this->num2 = num2;
            this->num3 = num3;
        }

        B(const B& other) : A(other.field1, other.field2, other.field3, other.num1)
        {
            num2 = other.num2;
            num3 = other.num3;
        }

        void show()
        {
            cout << num2 << " " << num3 << "\n";
            A::show();
        }
};

int main()
{
    string o = "TEXT 111";
    string *optr = &o;

    string n = "TEXT 222";
    string *nptr = &n;

    string *numptr = new string("9845947598375923843");

    A ba1(optr, nptr, numptr, 1000);
    ba1.show();

    A ba2(ba1);
    ba2.show();

    A ba3 = ba2;
    ba3.show();

    B vip1(20, 1000, optr, nptr, numptr, 3000);
    vip1.show();

    B vip2(vip1);
    vip2.show();

    delete numptr;
    return 0;
}

I DO understand that when I change from private to protected it should work (and works, of course) - but how to deal with the situation that I have in my code? The question is: how to initialize, in copy constructor, private fields from base class? I get the following errors with the current code:

/home/yak/test.cpp|9|error: ‘std::string* A::field1’ is private|
/home/yak/test.cpp|61|error: within this context|
/home/yak/test.cpp|10|error: ‘std::string* A::field2’ is private|
/home/yak/test.cpp|61|error: within this context|
/home/yak/test.cpp|11|error: ‘std::string* A::field3’ is private|
/home/yak/test.cpp|61|error: within this context|
/home/yak/test.cpp|12|error: ‘double A::num1’ is private|
/home/yak/test.cpp|61|error: within this context|
||=== Build failed: 8 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
yak
  • 3,770
  • 19
  • 60
  • 111
  • 1
    You make them `protected` as you've suggested, then access them from B's ctor body. What's the problem with making them `protected`? – RJFalconer Apr 07 '16 at 17:10
  • If you cannot change `A`, then what you're asking is impossible. And your code is leaking and not exception-safe. Why use pointers to strings?! – Christian Hackl Apr 07 '16 at 17:11
  • @RJFalconer: I'm curious, what I need to do to initialize `private` fields from the child class. As we see, with initialization list it does not work – yak Apr 07 '16 at 17:12
  • @ChristianHackl, of course it is possible! See my answer. (the pointer-to-string part is valid, of course) – SergeyA Apr 07 '16 at 17:13
  • @SergeyA: Yes, of course you can use `A`'s copy constructor. But you cannot initialise them directly. – Christian Hackl Apr 07 '16 at 17:14
  • @SergeyA: (ignoring the fact that `A` does not initialise any of its members anyway, because the constructors use assignments) – Christian Hackl Apr 07 '16 at 17:16
  • @ChristianHackl, unneccessary pedantic and moot, and seems to be spoken only to support your initial incorrect claim. – SergeyA Apr 07 '16 at 17:23
  • @SergeyA: I disagree. The OP apparently does not fully understand that `private` really means private, even for derived classes and constructors calling base constructors. – Christian Hackl Apr 07 '16 at 17:24
  • 1
    @ChristianHackl, OP explicitly accepted the answer below, and explained that they understood the issue fully. Op didn't need to access the fields, only to make sure they are initialized when child copy ctor is called, and didn't know how to call base copy ctor directly. – SergeyA Apr 07 '16 at 17:27

3 Answers3

6

All you need to do is call the copy constructor of A when you copy construct B like

B(const B& other) : A(other)
{
    num2 = other.num2;
    num3 = other.num3;
}

Since B inherits from A this is legal and A will copy the A part of other.

Also note that all of these pointer are unnecessary and make the code more complicated. We could rewrite it like:

class A
{
private:
    string field1;
    string field2;
    string field3;
    double num1;

public:
    A(const string& o, const string& n, const string& m, double a = 0) : field1(o), field2(n), feild3(m), num1(a) {}

    A(const A& other) field1(other.field1), field2(other.field2), feild3(other.feild3), num1(other.num1) {}

    void show()
    {
        cout << field1 << " " << field2 << " " << field3 << "\n";
    }
};

/*--------------------------------------------------------------------------------------------*/

class B : public A
{
private:

    double num2;
    double num3;

public:

    B(double num2, double num3, const string& o, const string& n, const string& m, double a = 0) : A(o, n, num, a), num2(num2), num3(num3) {}

    B(const B& other) : A(other), num2(other.num2), num3(other.num3) {}

    void show()
    {
        cout << num2 << " " << num3 << "\n";
        A::show();
    }
};
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

When using the copy constructor for class B, you should call the copy constructor for class A.

So, substitute your code by this one:

    B(const B& other) : A(other)
    {
        num2 = other.num2;
        num3 = other.num3;
    }

Also, declare the destructor from class A as virtual. And I suppose you also want to do that for show() method.

Daniel
  • 346
  • 3
  • 6
0

You need to invoke parent copy constructor from your copy constructor, giving it the same argument.

SergeyA
  • 61,605
  • 5
  • 78
  • 137