【问题标题】:Can't access derived class method from pointer of type base class无法从类型基类的指针访问派生类方法
【发布时间】:2014-06-22 18:18:53
【问题描述】:

我应该说明我对 OOP 有点陌生。 我正在尝试创建一个指向具有 GetName() 方法的 Person 类型指针的向量,并从派生 Person 的 Player 类访问方法 GetSpg()。我收到错误消息“GetSpg() 不是 Person 的成员”。我的问题是:有没有办法从向量中访问这两个函数,这样如果它指向一个 Person 就不会显示该方法,但如果它要这样做?

这是我的代码:

#ifndef _PERSON_H
#define _PERSON_H

#include <iostream>
#include <algorithm>

typedef std::pair<std::string, std::string> StrPair;

class Person :private StrPair
{

  public:
    Person(const std::string& fn = "none", const std::string& sn = "none")         :StrPair(fn,sn){};
    virtual void Update(const std::string& fn, const std::string& sn){ StrPair::first = fn; StrPair::second = sn; };
    virtual const StrPair& GetName(){ return (const StrPair&)(*this); };
};
#endif

typedef std::pair<int, int> IntPair;

class Jucator: public Person, private IntPair
{
    std::string tip;
    int spg;
    int average;

  public:
    Jucator(const std::string& fn = "none", const std::string& sn = "none", 
        const std::string& t = "", const int& _spg = 0, const int& _avr = 0, 
        const int& _g = 0, const int& _r = 0) :Person(fn, sn),tip(t),spg(_spg),average(_avr),IntPair(_g,_r){};
    virtual void Update(const std::string& fn, const std::string& sn, const std::string& t, const int& _spg, const int& _avr,
        const int& _g, const int& _r){
    Person::Update(fn, sn); tip = t; spg = _spg; average = _avr; IntPair::first = _g; IntPair::second = _r;
};

virtual const int& GetSpg(){ return spg; };

【问题讨论】:

  • 你永远不能从基类指针访问派生类方法,但是你可以反过来做
  • class Jucator: public Person, private IntPair 其中typedef std::pair&lt;int, int&gt; IntPair。继承 STL 比和魔鬼做交易更糟糕。
  • 我希望人们不要认为这“太琐碎”。我从经验中知道,很多人,尤其是从 Web 技术转向 C++ 的人,觉得这有点令人困惑。
  • @Sharadh 我不确定用户想要完成什么,他是在搜索矢量 还是他自己的类?为什么多态在这里没有帮助?我很困惑
  • @Marco 我也不确定,从他的代码。然而,从他所说的来看,他需要铸造和使用它。这里的多态性(我的意思是亲自拥有 GetSpg() 的存根实现,它什么都不做)似乎是人为的。我们在派生类之一中使用完全不相关的函数污染了基类。我看不到向量 OP 所指的位置正在使用。如果 OP 可以解释他的用例,也许我们可以做得更好?

标签: c++ oop vector stl dynamic-programming


【解决方案1】:

你不能。 Person 类型的指针只能用于访问属于 Person 对象的数据/地址(函数)。编译器根本无法知道从Person 派生的所有类可能是什么,因此哪些操作是合法的。

看看动态投射。 MSDN Reference | Tutorial

简而言之:

Player* pPlayer = dynamic_cast<Player*>(pPerson);
if (pPlayer) {
  //Use the pointer like a player pointer
  //Note: You can only call player functions from pPlayer, not pPerson
} else {
  //Use the pointer like a person pointer
}

请注意,此转换是运行时操作。在编译时,编译器会看到您使用 Player 指针来访问 Player 代码,这是很高兴允许的!

免责声明:我发现您的代码难以遵循,因此请将此视为对您问题的文字回答

【讨论】:

  • 只有当基类至少有一个虚函数时才能使用动态类型/转换(在这种情况下,建议析构函数是虚函数)。
  • 同意 - 我从来没有在没有 virtual 的情况下使用过它,所以刚刚学会了这一点。请在此处查看更多信息:stackoverflow.com/questions/2253168/… 谢谢@lrineau!
  • 感谢您的帮助。动态铸造完成了这项工作。我真的很困惑为什么我无法访问该方法。 cplusplus.com 的教程非常有用。
【解决方案2】:

您面临的问题与classic animal/cat/dog example 非常相似。基本思想是你有一个基类 - Animal - 和两个派生自它的类 - Cat 和 Dog。

class Animal {
    public:
    Animal() {}
    virtual ~Animal() {}
};

class Dog : public Animal {
    public:
    Dog() : Animal() {}

    void bark() { std::cout << "Woof" << std::endl; }

    ~Dog() {}
}

class Cat : public Animal() {
    public:
    Cat() : Animal() {}

    void meow() { std::cout << "Meow" << std::endl; }

    ~Cat() {}
}

现在,如果你声明一个 Cat 或 Dog 对象,很明显你可以调用 bark() 或 meow();但是如果你声明一个 Animal 对象,就无法知道它是 Cat 还是 Dog,所以你不能调用任何一个方法。

在您的情况下,您将 Person 作为基类,将 Player 作为派生类。您可以进一步派生 Person 并拥有一个新类 NonPlayer,这样 Person 将扮演与 Animal 相同的角色,而 Player 和 NonPlayer 将分别是 Cat 和 Dog。

如果您真的需要从指向 Person 对象的指针访问 Player 方法,则需要先将 Person* 强制转换为 Player*。但是,您需要先确定里面的指针是 Player*。如果不是,您很可能会收到编译错误。

【讨论】:

    【解决方案3】:

    有向上转换和向下转换的概念对于理解您的问题至关重要。可以使用dynmc_cast的概念,这个Link会有助于理解。

    【讨论】:

      猜你喜欢
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多