이 코드에서 가상 메소드를 호출 할 때 세그먼트 화 결함이 발생하는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/710607

문제

나는 여전히 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에서 이러한 개념을 아는 사람을 위해 일반적으로 상속 및 다형성 사용에 관한 다른 팁이 있다면 알려주십시오. 고맙습니다!

도움이 되었습니까?

해결책

이름 - 기본에서는 양의 지침이 있습니다

또한 또 다른 문제가 있습니다.

  Base c = Child("2");

나는 그것이 당신이 원하는 것이라고 생각하지 않습니다. 코드는 캐스트 된 아이의 기본 인스턴스를 만듭니다. 그러나 나는 당신이 기본 인터페이스를 기반으로 하위 인스턴스로 작업하고 싶다고 생각합니다. 대신 작성해야합니다.

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

또한 미래의 버그를 피하기 위해 기본의 파괴자를 가상으로 선언하십시오.

다른 팁

기본 Nenber 변수를 초기화하지 마십시오. 기본 생성자는 다음과 같습니다.

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

뿐만 아니라 당신이 말할 때

Base b = Child( "xxx" );

그러면 자식 인스턴스는 기지로 썰어지며 아마도 원하는 것이 아닐 것입니다.

나는 당신이 당신의 ctors의 무엇이든 멤버 char * 이름을 할당하고 있다고 생각하지 않습니다.

child :: disp () 메소드는 절대 호출되지 않습니다 - C는 포인터 나 참조가 아닌 유형 기반의 변수이므로 가상 메소드를 확인하지 않습니다.

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

아이에게 전화 할 것입니다 :: disp ().

우와 거기.

몇 가지 문제가 있습니다. 그러나 당신의 segfault는 아마 당신이 지나가기 때문일 것입니다 char* - 그것은 단지 포인터 일뿐입니다. cout 거기에 disp(). 문제는 그 포인터가 살지 않는다는 것입니다 disp(), 그것은 살고 있습니다 main(). 당신은 아마도 깊은 코피를 원할 것입니다 char*, 또는 사용 std::string. 이렇게하면 작동하지 않습니다.

편집하다:

편집 2를 참조하십시오

클래스에 이름을 할당 할 수는 없습니다. name 변하기 쉬운. 그렇게하면 예측할 수없는 결과를 얻을 수 있습니다. 아마도 여전히 segfault 일 것입니다. 기억하십시오 : C/C ++에서 힙에 할당되지 않으면 물체는 로컬로 스코핑됩니다. 이 경우 CTOR에서는 다음과 같은 작업을 수행하고 싶습니다.

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

그리고 파괴자에서는 다음과 같은 일을하고 싶을 것입니다.

delete [] this->name;

참고 : 내 구문은 완전히 잘못되었을 수 있으며, 위의 코드는 본질적으로 안전하지 않다는 것을 알고 있습니다. char* 널이 아닌지 확인하고 반환 값을 확인하지 않으려면 new. 그럼에도 불구하고, 이것은 당신이 시작해야합니다.

편집 2 :나는 수정했다. 문자열 리터럴은 지속적인 저장소로 취급되므로 프로그램 지속 시간 동안 살아갑니다. 그럼에도 불구하고, 내가 믿는 교훈은 중요하다. 일반적으로 문자열 리터럴을 다루지 않을 때, 포인터 (또는 배열 등)를 전달하려면 저장소를 할당해야합니다. 또한 상기 물체를 파괴 할 때 적절하게 배치해야합니다.

여기에는 문제가 거의 없습니다. 첫 번째는 기본 클래스 소멸자가 가상이어야한다는 것입니다. 그렇지 않으면 기본 클래스 소멸자는 파생 된 객체를 가리더라도 항상 호출됩니다. 둘째, 파생 클래스 객체를 기본 클래스 객체에 할당해서는 안된다는 것입니다. 이것을 물체 슬라이싱이라고합니다. 따라서 과제는 포인터 또는 참조를 통해 수행해야합니다.

세분화 문제는 쓰레기 가치가 포함되어 있기 때문에 발생합니다. 생성자에서 초기화해야합니다.

코드에 몇 가지 문제가 있습니다.

첫째, Segfault를 얻는 이유는 Base CTOR의 구현이 클래스 멤버 변수 중 하나와 동일한 이름의 매개 변수를 가져 오기 때문입니다.

class Base
{
protected:
  char *name;

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

CTOR의 매개 변수 '이름' 가죽 동일, erm ... 이름의 클래스 '회원 변수.

둘째, 당신은입니다 슬라이스 여기에 당신의 대상 :

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

'C'는 유형 기반이며 아이를 할당하려고합니다. 아이에게 고유 한 모든 것들은 oogbject를 기본 클래스에 할당 할 때 슬라이스됩니다.

다음은 다음과 같은 두 가지 문제를 해결하는 코드입니다.

#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;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top