2

I've got one base class/parent class: Person

And two subclasses/child classes: Player, Coach

This is what the header for the base class Person looks like:

class Person
{
    public:
        Person(string name);
        Person();
        virtual ~Person();
        string getName();
        void setName(string name);
        virtual void printSpec() const = 0;

    private:
        string name;
};

I tried to compile and run, it started complaining about this:

include\Person.h||In constructor 'Coach::Coach(std::string, std::string)':|
include\Person.h|19|error: 'std::string Person::name' is private|
\src\Coach.cpp|5|error: within this context|
||=== Build finished: 2 errors, 0 warnings ===|

And pointed to this:

private:
    string name;

In the context of one out of two constructors for the child class "Coach":

Coach::Coach(string name, string responsibility): Person(name){
    this->name = name;
    this->responsibility = responsibility;
}

However, it doesn't make the same complaint about that very same line in the constructor of the "Player"-class, only complains about "string name being a private member" in the constructor of the "Coach"-class.

I looked up some solutions for other people, tried protected instead of private, tried changing the names of the variables, but to no use.

What gives?

user1770094
  • 87
  • 1
  • 3
  • 8
  • 1
    If you are already calling Person(name) in the Coach constructor, why do you need to set this->name at all? I assume Person::Person takes care of that? In any case, protected scope should work. – Vivek Aug 27 '13 at 15:36
  • Get a [decent book on C++](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). `Player::name` is private. if you want derived classes to have member-level access (and there is no reason to in this case, but thats another matter) it needs to be *protected* or *public* or *friend*-ed (the latter highly unusual for derived classes). – WhozCraig Aug 27 '13 at 15:36
  • How do you declare the Coach class? (Don't forget to use the public word in there too) – doctorlove Aug 27 '13 at 15:39
  • I've got it working now with protected, thanks. There's some example code that I've got, and it has private members and two subclasses who use the member without a hitch. Or I must've missed some trick in it to get it all to work, or perhaps it was all precompiled. Anyhow, problem solved now. – user1770094 Aug 27 '13 at 15:52
  • 1
    **Don't** make it protected. The constructor for `Person` will initialize it. – Pete Becker Aug 27 '13 at 16:05

3 Answers3

6

A private member cannot be accessed by derived class.

The solution could be to use the member-initialization-list to do that :

Coach::Coach(string name, string responsibility): Person(name){
    //                                            ^^^^^^^^^^^^
    //                     Initialize the name through the base class constructor
    this->responsibility = responsibility;
}

Because Person is the base-class and have a constructor that takes a name, you can do it that way. You don't need to access the name member from the derived class.


Another solution could be to set this member protected (the first solution is still better).

class Person
{
    public:
        Person(string name);
        Person();
        virtual ~Person();
        string getName();
        void setName(string name);
        virtual void printSpec() const = 0;

    protected:
//  ^^^^^^^^^
        string name;
};

You can take a look here, the inheritance part talk about access-type.


Not to answer the question but for some good practice, I would suggest you to pass your string parameter as const reference. It is a better practice :

Coach::Coach(const string& name, const string& responsibility): Person(name){
    //       ^^^^^       ^       ^^^^^       ^
    this->responsibility = responsibility;
}
Community
  • 1
  • 1
Pierre Fourgeaud
  • 14,290
  • 1
  • 38
  • 62
  • `Coach` **is** derived from `Person`, so the constructor is the right approach. Changing `name` to `protected` is **wrong**. The constructor can initialize the member, and the `setName` member function can be used to set it later if needed. – Pete Becker Aug 27 '13 at 16:09
  • @PeteBecker You are right, I edited my post to make it more appropriate. Thanks for pointing this out. – Pierre Fourgeaud Aug 27 '13 at 16:12
2

name is private in the base class, so you can't access it from a derived class.
Assuming that Coach derives publically from Person you could make the member variable protected, but fortunately the Person constructor takes a name, so you don't need to access it from the derived classes directly. You can use the initialiser list as you are doing and therefore don't need to set it twice

Coach::Coach(string name, string responsibility)
                   : Person(name){
                 //  ^^^^^^^^^^^^
                 // Sends name to Person's constructor
    this->responsibility = responsibility;
}
doctorlove
  • 18,872
  • 2
  • 46
  • 62
  • `Coach` does not need to derive **publicly**; as long as `Person` is a base class, it can be initialized in the initializer list. – Pete Becker Aug 27 '13 at 16:06
0

Change "private" to "protected" private means no other part of the system, including derived classes, can access the member.

Dale Wilson
  • 9,166
  • 3
  • 34
  • 52
  • 1
    **Don't** change it to protected. The constructor for `Person` initializes `name`, and the `setName` member function changes it if needed. There is no reason to use `protected` here. – Pete Becker Aug 27 '13 at 16:14
  • Agreed. I was just addressing "why does the compiler generate an error". Using an accessor method is better (in this case) than protected. – Dale Wilson Aug 27 '13 at 18:02