C++ C++;派生类调用基类方法给出分段错误

C++ C++;派生类调用基类方法给出分段错误,c++,C++,假设我有一个基类和派生类,如下所示: #include "Sprite.h" class Base{ private: int X; //location Sprite* sprite; public: Base(Sprite* sprite){ sprite = new Sprite(some parameter); } int getLocation(){ return X; } int ge

假设我有一个基类和派生类,如下所示:

#include "Sprite.h"
class Base{
  private:
    int X; //location
    Sprite* sprite;
  public:
    Base(Sprite* sprite){
        sprite = new Sprite(some parameter);
   }
    int getLocation(){
           return X;
    }
    int getWidth(){
         return sprite->getWidth();
    }
}


 class Derived : public Base{
    private:
      Sprite* sprite;  // here I have to redefine it in constructor
    public:
      Derived(Sprite* sprite);  // it's different that base constructor
 { sprite = new Sprite(some parameter);
   sprite->setPriperty(some parameter);
}
 }
Base::Base(Sprite* sprite) {
    this->sprite = sprite;
}

当我从其他位置调用派生::getLocation()时,没有错误。但是当我调用派生的::getWidth()时,它给了我分段错误。我必须从基类复制相同的代码(即将getWidth的代码复制到派生类中),以避免错误。我还尝试使用“using Base::getWidth;”,但仍然给了我分段错误。似乎如果基类方法包含指针t

,您可能忘记了在构造函数中设置
sprite
成员变量。这样做:
Base(Sprite*s):Sprite(s){}
Base(Sprite*s){this->Sprite=s;}

Derived(Sprite*Sprite)
构造函数应该像这样将
Sprite
传递给父构造函数:
Derived(Sprite*Sprite):Base(Sprite){}


请注意,就目前情况而言,
基本
构造函数必须从
派生
构造函数传递一个有效的
Sprite*
,以便
getLocation()
处理
派生

的实例,因此首先-什么是分段错误?它类似于Java中的
NullPointerException
,或者C#中的
NullReferenceException
。当您试图访问未分配的内存时,就会发生这种情况

为什么会这样?您忘了为
sprite
指针分配内存,因此它指向一些不精确的内存块。您应该使用
new
操作符在构造函数中初始化它,如下所示:

Base::Base(Sprite* sprite) {
    this->sprite = new Sprite(sprite);
}
Derived(Sprite* sprite): Base(sprite) {
   ...
}
如果你喜欢危险地生活,你也可以做以下事情:

#include "Sprite.h"
class Base{
  private:
    int X; //location
    Sprite* sprite;
  public:
    Base(Sprite* sprite){
        sprite = new Sprite(some parameter);
   }
    int getLocation(){
           return X;
    }
    int getWidth(){
         return sprite->getWidth();
    }
}


 class Derived : public Base{
    private:
      Sprite* sprite;  // here I have to redefine it in constructor
    public:
      Derived(Sprite* sprite);  // it's different that base constructor
 { sprite = new Sprite(some parameter);
   sprite->setPriperty(some parameter);
}
 }
Base::Base(Sprite* sprite) {
    this->sprite = sprite;
}
但这并不安全,因为sprite可以在堆栈上分配,所以这样的代码可能会破坏程序,导致未定义的行为:

Base * getBase() {
    Sprite sprite;
    //some code operating on sprite
    return new Base(&sprite);
}
这是危险的,因为退出
getBase
函数后,内存中不再有
sprite

更新:

因此,基本上我从您的评论中得出的结论是,您没有调用
Base
类的正确构造函数。您的
派生的
构造函数应该如下所示:

Base::Base(Sprite* sprite) {
    this->sprite = new Sprite(sprite);
}
Derived(Sprite* sprite): Base(sprite) {
   ...
}
如果不这样做,则不会为基类设置
sprite
的值。派生类的
sprite
字段只是隐藏了
Base
类的
sprite
字段。就像:

int i = 0;
void fun() {
    int i = 20;
}
在本例中,全局
i
没有更改,因为它被阴影遮挡


您的代码在复制
派生类中的
getWidth()
方法后工作,因为它当时正在访问
派生类的
sprite
字段。需要明确的是,在不重写方法的情况下,
getWidth()
正在访问
Base
类的
sprite
字段,当您重写它时,它将访问
派生的
类的字段。

“…没有错误”-您知道。在这里定义一些理智。这里应该管理两个
Sprite
实例吗?一个由
Base::sprite
指向,另一个由
Derived::sprite
指向?如果没有,那么您托管了太多的
Sprite*
。请在你的问题中加入一个。为什么他们都有一个同名的不同的精灵?只有一个精灵类。但是,在派生类中,在初始化私有sprite成员后,必须使用sprite的方法设置一些额外的属性。因此构造函数不同于基类。因此,我必须在派生类中声明它。我们也许能帮上忙。我把代码贴出来了。如果仍然不够,我将回家获取更多的代码。如果您正在发布答案,您需要解决Sprite*的其他问题。请至少提到三条规则。:)我在基类中初始化了精灵,这是一般的移动对象。在派生类,即播放器类中,我也定义了精灵类,但不是通过基类构造函数,我只是像在基类中一样调用精灵构造函数。这很重要吗?@ohmygoddess,是的,因为当您调用
getLocation()
时,它只会看到
Base
类的
Sprite*Sprite
。因此,像您这样做意味着它永远不会看到,因此也永远不会使用您为
派生的
实例创建的实例。@KennyOstrom,这就是为什么我现在有点不愿意讨论第三条规则的原因,因为似乎有一个更基本的问题“挂起,哪些成员在哪个上下文/函数中可见”。第三条规则是下一步,尽管私有/删除的副本构造函数可能更合适……所以在这种情况下,如果我声明和定义的sprite类不同于基类,那么我不能调用方法getWidth?因为没有“基”类精灵,只有“派生”类精灵?我使用new关键字初始化指针,请参阅更新的代码。如果我在派生类中复制基类的代码,一切都正常。getWidth方法。如果我在派生类中复制它,一切正常。但是我认为我不需要这样做,因为。因为inherenceSo这是否意味着如果我重写基类的私有成员,我必须重写任何调用它的方法。私有成员?我想这可能就是为什么我必须将代码复制到派生的classIt中的原因。这意味着没有什么比重写私有成员更重要的了——您只是从基类中隐藏了字段。您只是没有初始化基类中的字段,而是初始化了派生类中的字段。字段的行为不具有多态性,因此
Base::getWidth()
方法正在访问
sprite
字段,该字段位于
Base
类中,而只有
派生的
类的字段被初始化。如果你愿意