C ++友谊/多态类错误

时间:2013-12-25 12:45:42

标签: c++ class polymorphism friend access-control

在C ++中,我使用多态类和友谊来建立一个基本的“朋友组”。但是,当我试图访问班级人员的私人年龄功能时,我是班级男孩的朋友,我无法访问它。有什么问题?

/* 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);
}

2 个答案:

答案 0 :(得分:0)

技术问题:

c ++友谊是单向的。

尝试protected以授予对派生类的访问权。

代码审查:

/* Polymorphic Classes and Class Friendship */

在C ++中避免使用C /* ... */ 多行注释是个好主意,因为它们不会嵌套,而且有些/很多程序员会将它们用于注释掉代码以进行调试。

相反,优先使用C ++ //(单一)行注释

#include <iostream>

行。

class Person{
public:

行。

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

第一个参数应为char const*。例如,在使用符合C ++ 11的编译器时,如果没有const,则无法传递文字字符串。

    char* Name;

这里的原始指针需要匹配构造函数形式参数。

实际上,它被初始化为构造函数指针参数的简单副本的方式,它将任何Person实例的生命周期限制为实际参数的生命周期。

std::string是一种更灵活,更无问题的选择。

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

由于此函数不是const,因此无法在const对象上调用它。

此外,void是C-ism,在C ++中是非常好的。

在C中它表示此函数不带任何参数。在C ++中,这是不必要的,即void是不必要的措辞。此外,C甚至没有会员功能。

    virtual ~Person(void){delete this;}

同样,void是不合时宜的。

delete this在这种背景下非常不合适。

private:
    int Age;

唯一的问题是未能为数据成员应用某些命名约定。例如,如age_(请注意,下划线位于结束),或类似my_agemyAge

};

行。

class Boy : public Person{

行。

friend class Person;

毫无意义,因为类Person不能访问此类中的任何内容。

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

同样,应该是char const*。或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;
    }

这里,如果编译器支持它,请添加override以使编译器检查您是否真正覆盖基类函数,如void Speak() override {

换句话说,抛弃void这是不必要的C-ism措辞,但确实添加了override,这非常有用。

    ~Boy(void){delete this;}

void是不合时宜的。

delete this在这种背景下非常不合适。

private:
    Person* MyFriend;

如前所述,这再次限制了Boy实例的生命周期。

};

行。

int main(void){

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();

不要明确调用析构函数。好吧,一个非常有经验的程序员可能会在使用展示位置new进行分配时这样做:因为某种原因,它在语言中。但作为初学者,即使有一两年的专业经验,也不要这样做。

    return (0);

技术上可行,但不必要。 main默认返回0.

}

答案 1 :(得分:0)

您已指定PersonBoy的朋友,但您希望Boy成为Person的朋友。但是没有必要使用友谊。 Boy已经继承了Person,因此如果您将age声明为protected,则Boy可以看到它。