【问题标题】:C++ Friendship / Polymorphic Classes ErrorC++友谊/多态类错误
【发布时间】:2014-01-13 09:45:51
【问题描述】:

在 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);
}

【问题讨论】:

  • 您的代码有很多错误,因此唯一明智的建议是让您花一些时间学习 C++ 的基础知识。见this list of C++ books

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


【解决方案1】:

技术问题:

c++ 友谊是单向的。

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

代码审查:

/* Polymorphic Classes and Class Friendship */

在 C++ 中避免使用 C /**/ multiline cmets 是个好主意,因为它们不嵌套,并且一些/许多程序员使用它们来注释掉 em> 调试代码。

而是优先使用 C++ // (single-) line cmets

#include <iostream>

好的。

class Person{
public:

好的。

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

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

    char* Name;

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

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

std::string 是一个更加灵活且没有问题的选择。

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

因为这个函数不是const,所以不能在const对象上调用。

另外,void 是 C 主义,在 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&amp;

    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。

}

【讨论】:

  • 不显式调用析构函数是什么意思,delete this 不好?我该如何纠正?如果您可以解释并附加答案,则 +1 并接受答案
  • 析构函数被自动、隐式地调用,例如通过delete 表达式。由于您使用的是new,因此您还应该使用delete,或者更好的是像std::unique_ptr 这样的智能指针。但是,在上面的程序中,不需要动态分配,这只是Java 主义。你可以声明Person John;。它也比new 快几个数量级。
  • 关于“+1 和接受的答案如果...”,那真是太愚蠢了。如果您对 SO 代表较低的人这样做,那可能真的会让那个人感到羞耻。而不是因为那个人会为他或她的低代表感到羞耻。但是因为那些在这里和其他网络地方帮助他人的人不是受假货币或其他任何东西的驱使(相反,整个计划的目的是破坏准确性和可靠性答案)。所以,请在以后写之前考虑一下。
  • 顺便说一句,请考虑使用您的真实姓名。如果有更多的人开始使用他们的真实姓名,那就更好了。不是(不经意间)表明他们正在做他们不想与真实自我相关联的事情,甚至一些 SO 模组也会这样做......
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2014-09-30
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多