无法在构造函数中访问类的继承成员

Posted

技术标签:

【中文标题】无法在构造函数中访问类的继承成员【英文标题】:Can't access inherited members of class in constructor 【发布时间】:2016-06-27 19:33:40 【问题描述】:

我是 C++ 新手。我有简单的 Unit 类和 hero 类,它们是 Unit 类的继承。 Hero 类有 2 个附加参数,但构造函数无法访问父类的参数。 这是unit.hpp:

#ifndef UNIT_HPP
#define UNIT_HPP

#include <string>

using namespace std;

class Unit

public:
    unsigned short  max_health  = 100;
    string          name        = "Dummy";
    short           health      = 100;
    short           damage      = 10;
    bool            isDead      = 0;

    Unit();
    Unit(string, unsigned short, unsigned short);
;

#endif //UNIT_HPP

这里是unit.cpp:

#include <string>
#include <iostream>

#include "unit.hpp"

using namespace std;

Unit::Unit()

    cout << "Dummy was created!" << endl;
;

Unit::Unit(string N, unsigned short HP, unsigned short AT):
    max_health(HP),
    name(N),
    health(HP),
    damage(AT)

    cout << N << " was created!" << endl;
;

这里是 hero.hpp:

#ifndef HERO_HPP
#define HERO_HPP

#include <string>

#include "unit.hpp"

class Hero : public Unit

public:
    unsigned short  max_mana    = 100;
    string          name        = "The Brave Warrior";
    short           mana        = 100;

    Hero (string, unsigned short, unsigned short, unsigned short);

;

#endif //HERO_HPP

最后,这里是 hero.cpp:

#include <string>

#include "hero.hpp"

using namespace std;

Hero::Hero(string N, unsigned short HP, unsigned short MP, unsigned short AT):
    max_health(HP),
    max_mana(MP),
    name(N),
    health(HP),
    mana(MP),
    damage(AT)

    cout << "The Legendary Hero, " << N << ", was born!" << endl;

这是控制台输出:

src/hero.cpp: In constructor ‘Hero::Hero(std::__cxx11::string, short unsigned int, short unsigned int, short unsigned int)’:
src/hero.cpp:10:5: error: class ‘Hero’ does not have any field named ‘max_health’
     max_health(HP),
     ^
src/hero.cpp:13:5: error: class ‘Hero’ does not have any field named ‘health’
     health(HP),
     ^
src/hero.cpp:15:5: error: class ‘Hero’ does not have any field named ‘damage’
     damage(AT)
     ^

问题出在哪里?抱歉英语不好。我希望我问的问题是对的,对我来说有这么多新术语。先感谢您。

【问题讨论】:

您想从初始化列表中调用基类构造函数,或者您可以在派生构造函数的主体中访问这些成员。 如果你想使用空间节省数据类型,你应该使用uint#_t类型,例如uint8_tuint16_t。这些类型有保证的大小。 short 类型保证至少具有给定的范围;它可以支持更大。例如,一个 32 位整数可以用作 short 并且仍然在语言规则范围内。 【参考方案1】:

你的基类应该负责初始化它的变量,通常是通过一个构造函数方法。

这个:

unsigned short  max_health  = 100;
string          name        = "Dummy";
short           health      = 100;
short           damage      = 10;
bool            isDead      = 0;

看起来不洁净。这些成员应该在构造函数中初始化:

Unit::Unit()
: max_health(100),
name("Dummy"),
health(100),
damage(10),
isDead(false)
 ; 

另外,对于bool 变量,您应该使用truefalse,而不是数字。

编辑 1:重复的成员名称 您的子类应避免使用与基类相同的变量名。

英雄中的台词:

  string name;

隐藏或隐藏基类成员:

  string name;

如果你更愿意遵守这个约定,你应该使用 范围解析操作符 :: 告诉编译器你指的是哪个成员:

Hero::name = "Hercules"; // Assign member in Hero class
Unit::name = "Person";   // Assign to member in Unit class.   

【讨论】:

顺便说一句,没有必要使用 short 数据类型,除非您在内存受限的系统上。 int 类型通常是处理器寄存器或字大小的类型。所以在 32 位平台上,处理器的寄存器大小通常是 32 位。使用较小的变量(字符除外)不会显着节省空间或提高效率。 感谢您的建议!我使用 short 只是因为我的系统是 x64 并且我想限制最大健康,所以它不会超过 9000 :) 另外,我删除了重复项。 如果这个答案有帮助,请点击复选标记。 这很有帮助,但对我的问题没有帮助。 Evan 的解决方案修复了它。【参考方案2】:

C++ 不允许您从子类的初始化列表中初始化基类的成员。

Hero::Hero(string N, unsigned short HP, unsigned short MP, unsigned short AT):
    Unit(N, HP, AT), // initializes the base class' members
    max_mana(MP),
    name(N),
    mana(MP),

    // but you could override the base class' members here
    isDead = true;
    cout << "The Legendary Hero, " << N << ", was zombified!" << endl;

此外,您在 Unit 和 Hero 中都有一个名为“name”的成员,您可能希望删除或重命名其中之一。

【讨论】:

【参考方案3】:

在 Unit 的构造函数中初始化 Unit 的成员(如果你只想从 Hero 中调用它,可能是一个受保护的成员),以及在 Hero 中的 Hero 的成员。这就是初始化列表的工作方式。或者,您可以在 Hero 的 ctor 的大括号之间初始化它们,但不建议这样做。

【讨论】:

【参考方案4】:

您在 Hero.cpp 构造函数中尝试做的是初始化基类的成员。这听起来很像基类本身的工作!事实上,当到达分号时,可以说,基类构造函数 Unit() 已经被调用(因此,它包含的内容已经被初始化)。所以,如果你从 Unit 中删除 Unit(),你会得到一个编译错误,因为另一个构造函数有参数要接受。而那些你必须像这样明确指定的:

Hero::Hero(string N, unsigned short HP, unsigned short MP, unsigned short AT):
    Unit(HP, N, HP, AT),
    max_mana(MP),
    mana(MP),
    

请注意,这里根本没有调用 Unit() - 只有另一个构造函数是 - 显式调用的。

【讨论】:

以上是关于无法在构造函数中访问类的继承成员的主要内容,如果未能解决你的问题,请参考以下文章

Jave 类的继承

子类从父类继承过来的方法可以操作子类自己定义的成员变量吗

4月14日继承与多态

C++基类和派生类的构造函数

继承中的构造析构函数调用顺序

继承,虚继承机制