为什么在这段代码中调用虚拟方法时会出现分段错误?

发布于 2024-07-17 05:56:21 字数 980 浏览 9 评论 0原文

我还在学习C++; 我正在尝试多态性的工作原理,并且在调用虚拟方法时遇到分段错误。

(注意:我没有将析构函数标记为虚拟,我只是想看看会发生什么。)这是代码:

#include <iostream>

using namespace std;

class Base
{
protected:
  char *name;

public:
  Base(char *name)
  {
    cout << name << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

另外,如果您对了解继承和多态性的使用有任何其他提示, Java中的这些概念,请告诉我。 谢谢你!

I'm still learning C++; I was trying out how polymorphism works and I got a segmentation fault when calling a virtual method.

(Note: I didn't mark the destructor as virtual, I was just trying out to see what happens.) Here's the code:

#include <iostream>

using namespace std;

class Base
{
protected:
  char *name;

public:
  Base(char *name)
  {
    cout << name << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

Also, if you've any other tips regarding the usage of inheritance and polymorphism in general for someone who knows these concepts in Java, please let me know. Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

故人的歌 2024-07-24 05:56:22

name - 在 Base 中未初始化,

您还有另一个问题:

  Base c = Child("2");

我认为这不是您想要的。 您的代码将从已转换的 Child 创建 Base 的实例。 但我认为你想使用基于 Base 接口的 Child 实例; 你应该写:

  Base *c = new Child("2");

另外,为了避免未来的错误,将基类中的析构函数声明为虚拟的。

name - is unintialized in Base

also you have another problem:

  Base c = Child("2");

I don't think it's what you want. Your code will create an instance of Base from casted Child. But I think you want work with Child instance based on Base interface; you should instead write:

  Base *c = new Child("2");

also, to avoid future bugs, declare destructor in base as virtual.

客…行舟 2024-07-24 05:56:22

您永远不会初始化基本 nenber 变量 - 您的基本构造函数应该是:

Base(char * aname) : name( aname )
  {
    cout << name << ": Base class cons" << endl;
  }

除此之外,当您说

Base b = Child( "xxx" );

那么 Child 实例将被切片为 Base 时,这可能不是您想要的。

You never initialise the base nenber variable - your base constructor should be:

Base(char * aname) : name( aname )
  {
    cout << name << ": Base class cons" << endl;
  }

As well as that, when you say

Base b = Child( "xxx" );

then the Child instance will be sliced down to a Base, which is probably not what you want.

呢古 2024-07-24 05:56:22

我认为您没有将成员 char * 名称分配给您的 ctors 中的任何内容。

I don't think you're assigning the member char * name to anything in your ctors.

萌化 2024-07-24 05:56:22

Child::disp() 方法永远不会被调用 - c 是 Base 类型的变量,而不是指针或引用,因此它不会检查虚拟方法。

Base * c = new Child("1");
c->disp();
delete c;

会调用 Child::disp()。

The Child::disp() method will never be called - c is a variable of type Base, and not a pointer or reference, so it won't check for virtual methods.

Base * c = new Child("1");
c->disp();
delete c;

would call Child::disp().

卖梦商人 2024-07-24 05:56:22

哇在那里。

有一些问题,但是你的段错误可能是因为你传递了一个char*——它只是一个指针,然后尝试coutdisp()。 问题是,该指针并不存在于 disp() 中,而是存在于 main() 中。 您可能想要深度复制 char*,或使用 std::string。 这样做是行不通的。

编辑

参见编辑2

您不能只将名称分配给类的name 变量。 如果你这样做,你会得到不可预测的结果 - 并且你可能仍然会出现段错误。 请记住:在 C/C++ 中,对象的作用域是本地的,除非在堆上分配。 在这种情况下,在您的构造函数中,您需要执行以下操作:

this->name = new char[ strlen( name ) + 1 ];
strcpy( this->name, name );

在析构函数中,您需要执行以下操作:

delete [] this->name;

注意:我的语法可能完全错误,并且我意识到上面的代码本质上是不安全的,因为您没有检查 char* 以确保它不为 NULL,也没有检查 new 的返回值。 尽管如此,这应该可以帮助您开始。

编辑2:
我纠正了。 字符串文字被视为常量存储,因此在程序运行期间一直存在。 尽管如此,我认为这个教训很重要:一般来说,当不处理字符串文字时,传递指针(或数组等)时,您需要分配它的存储和深复制。 在销毁所述对象时,您还需要适当地取消分配。

Whoa there.

There's a few problems, but your segfault is probably because you're passing a char* -- which is just a pointer, and then trying to cout it in disp(). Problem is, that pointer does not live in disp(), it lives in main(). You probably want to either deep-copy the char*, or use std::string. Doing it this way will not work.

EDIT:

See EDIT 2

You can not just assign name to the class's name variable. If you do that, you'll get unpredictable results - and you'll probably STILL segfault. Remember: in C/C++, objects are locally scoped unless allocated on the heap. In this case, in your ctor, you'd want to do something like:

this->name = new char[ strlen( name ) + 1 ];
strcpy( this->name, name );

And in the destructor, you'll want to do something like:

delete [] this->name;

Note: my syntax may be completely wrong, and I realize the above code is inherently unsafe as you're not checking the char* to make sure it's not NULL, and you're not checking the return value of new. Nevertheless, this should get you started.

EDIT 2:
I stand corrected. String literals are treated as constant storage and thus live on for the duration of the program. Nevertheless, the lesson, I believe, is important: in general, when not dealing with string literals, passing a pointer (or array, etc.), you need to allocate storage for it and deep-copy. You also need to de-allocate appropriately when destroying said object.

初雪 2024-07-24 05:56:22

这里几乎没有问题。 首先,你的基类析构函数必须是虚拟的。 否则,即使基类析构函数指向派生对象,也将始终被调用。 其次,不应将派生类对象分配给基类对象。 这称为对象切片。
因此,赋值应该通过指针或引用来完成。

发生分段问题是因为它包含垃圾值。 您需要在构造函数中对其进行初始化。

There are few problems here. The first thing is your base class destructor has to be virtual. Otherwise your base class destructor will always be called even if it points to derived object. Second is you should not assign derived class object to base class object. This is called object slicing.
So, assignment should be done through pointer or reference.

The segmentation problem is happening because it contains garbage value. You need to initialize it in the constructor.

复古式 2024-07-24 05:56:22

您的代码存在一些问题。

首先,您遇到段错误的原因是 Base ctor 的实现采用与类成员变量之一同名的参数:

class Base
{
protected:
  char *name;

public:
  Base(char ***name**)
  {
    cout << name << ": Base class cons" << endl;
  }

ctor 的参数“name”隐藏该类' 相同的成员变量,呃...名称。

其次,您在此处切片您的对象:

int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

'c'是输入 Base,并且您正在尝试为其分配一个 Child。 当您将 ogbject 分配给基类时,Child 特有的所有内容都将被删除。

这是解决这两个问题的代码:

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    std::string name_;

public:
  Base(char *name)
      : name_(name) {
    cout << name_ << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name_ << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name_ << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name_ << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name_ << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name_ << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base * c = new Child("2");
  c->disp();
  delete c;
}

You have a couple of problems with your code.

First, and the reason why your getting a segfault, is the implementation of the Base ctor takes a parameter of the same name as one of the class' member variables:

class Base
{
protected:
  char *name;

public:
  Base(char ***name**)
  {
    cout << name << ": Base class cons" << endl;
  }

The ctor's parameter 'name' hides the class' member variable of the same, erm... name.

Second, you are slicing your object here:

int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

'c' is of type Base, and you are trying to assign a Child to it. All of the stuff that is unique to Child will be sliced off when you assign the ogbject to the base class.

Here is code that fixes both these problems:

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    std::string name_;

public:
  Base(char *name)
      : name_(name) {
    cout << name_ << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name_ << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name_ << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name_ << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name_ << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name_ << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base * c = new Child("2");
  c->disp();
  delete c;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文