0

In C++, I am using polymorphic classes and friendship to make a basic 'friends group'. However, when I am trying to access the private age function of the class person, which is a friend of the class Boy, I cannot access it. What is the problem?

/* Polymorphic Classes and Class Friendship */
#include <iostream>
class Person{
public:
    Person(char* name, int age) : Name(name), Age(age){}
    char* Name;
    virtual void Speak(void){
        std::cout << "I am a person called " << Name << std::endl;
    }
    virtual ~Person(void){delete this;}
private:
    int Age;
};
class Boy : public Person{
friend class Person;
public:
    Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}
    void Speak(void){
        std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
    }
    ~Boy(void){delete this;}
private:
    Person* MyFriend;
};
int main(void){
    Person* John = new Person("John", 12);
    Boy* James = new Boy("James", 14, John);
    Boy* Keith = new Boy("Keith", 18, James);
    John->Speak();
    James->Speak();
    John->~Person();
    James->~Boy();
    Keith->~Boy();
    return (0);
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user2976089
  • 347
  • 1
  • 5
  • 14
  • 3
    There is so much wrong with your code that the only sensible suggestion is for you to take some time to learn the basics of C++. See [this list of C++ books](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – juanchopanza Dec 25 '13 at 12:48

2 Answers2

1

technical problem:

c++ friendship is one-way.

try protected to give access to derived classes.

code review:

/* Polymorphic Classes and Class Friendship */

It's a good idea to avoid C /**/ multiline comments in C++, because they do not nest, and some/many programmers use them to comment out code for debugging.

Instead preferentially use C++ // (single-) line comments.

#include <iostream>

OK.

class Person{
public:

OK.

    Person(char* name, int age) : Name(name), Age(age){}

The first argument should be char const*. Without the const you will, for example, not be able to pass a literal string, when using a C++11-conforming compiler.

    char* Name;

The raw pointer here needs to match the constructor formal argument.

Effectively, the way that it's initialized as a simple copy of the constructor's pointer argument, it limits the lifetime of any Person instance to the lifetime of the actual argument.

A std::string is a far more flexible and unproblematic choice.

    virtual void Speak(void){
        std::cout << "I am a person called " << Name << std::endl;
    }

Since this function is not const, it cannot be called on a const object.

Also, the void is C-ism, ungood in C++.

In C it says that this function does not take any arguments. In C++ that's unnecessary, i.e. that void is needless verbiage. Besides, C doesn't even have member functions.

    virtual ~Person(void){delete this;}

Again, the void is ungood.

The delete this is extremely ungood in this context.

private:
    int Age;

The only problem with this is failure to apply some naming convention for data members. For example, like age_ (note that the underscore then goes at the end), or like my_age or myAge.

};

OK.

class Boy : public Person{

OK.

friend class Person;

Meaningless, since class Person doesn't access anything from this class.

public:
    Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}

Again, should be char const*. Or std::string const&.

    void Speak(void){
        std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
    }

Here, if the compiler supports it, do add an override in order to have the compiler check that you're really overriding a base class function, like void Speak() override {.

In other words, ditch the void which is needless C-ism verbiage, but do add the override, which is very useful.

    ~Boy(void){delete this;}

The void is ungood.

The delete this is extremely ungood in this context.

private:
    Person* MyFriend;

As earlier, this again limits the lifetime of a Boy instance.

};

OK.

int main(void){

The void is ungood.

    Person* John = new Person("John", 12);
    Boy* James = new Boy("James", 14, John);
    Boy* Keith = new Boy("Keith", 18, James);
    John->Speak();
    James->Speak();
    John->~Person();

So far OK.

    James->~Boy();
    Keith->~Boy();

Don't ever call destructors explicitly. Well, a really good experienced programmer might do that when using placement new for allocation: it is in the language for a reason. But as a beginner, and even with a year or two professional experience, don't do that.

    return (0);

Technically OK but unecessary. main returns 0 by default.

}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • What do you mean by not calling the destructors explicitly, and the `delete this` being bad? How would I correct that? +1 and accepted answer if you can explain and append answer – user2976089 Dec 25 '13 at 13:49
  • Destructors are called automatically, implicitly, for example by a `delete` expression. Since you're using `new` you should also use `delete`, or, better, a smart pointer like `std::unique_ptr` that does that for you. However, in the program above there *is no need to allocate dynamically*, that's just a Java-ism. You can just declare `Person John;`. It's also some orders of magnitude faster than the `new`. – Cheers and hth. - Alf Dec 25 '13 at 13:59
  • Regarding the "+1 and accepted answer if...", that's pretty darn silly. If you do that to someone with low SO rep it might really shame that person. And not because that person would be ashamed of his or her low rep. But because those who help others, here and in other net places, are ***not*** motivated by fake currency or whatever (rather, the whole scheme serves to undermine the accuracy and dependability of the answers). So, please do think before writing such, in future. – Cheers and hth. - Alf Dec 25 '13 at 14:02
  • By the way, do think about using your real name. It would be so much better if significantly more folks started using their real names. Not (inadvertently) signaling that they're doing things they do not want to have associated with their real selves, which even some SO mods do... – Cheers and hth. - Alf Dec 25 '13 at 14:08
0

You have specified that Person is a friend to Boy, but you want Boy to be friend of Person. However there's no need to use friendship. Boy already inherits Person thus if you declare age as protected class Boy can see it.

atoMerz
  • 7,534
  • 16
  • 61
  • 101