2014-07-11 4 views
-1

다른 질문에서이 문제를 읽었지만 비슷한 것은 없었습니다. 일부는 생성자에서 가상 메서드를 호출하고 나머지는 순수 가상을 호출했습니다. 그러나 여기에있는 질문은 순수하지만 모든 파생 클래스에서 구현할 필요가없는 가상 메서드에 대한 정보를 제공합니다. 인스턴스화 된 클래스가 메소드를 구현하지 않는 경우 호출하면 기본 메소드에서 메소드를 논리적으로 호출하며 때로는 충돌합니다. 궁금 해서요, 왜? VTABLE (입력되는 곳)은 무엇입니까? 그리고 그것을 해결하는 가장 좋은 방법은 무엇입니까.가상 메서드를 호출 할 때 충돌이 발생합니다.

이것은 간단한 예입니다 (순수 가상과 같은 대답은 피하십시오).

#include <iostream> 

class Foo 
{ 
public: 
    virtual std::string myString() {} 
}; 

class Bar : public Foo 
{ 
public: 
}; 

int main(int argc, char ** argv) 
{ 
    Foo * bar = new Foo; 
    bar->myString(); 

    return 0; 
} 

최상의 해결책은 무엇입니까?

  1. 던져 주장 사용하여 예외
  2. (false)를
  3. 은 기본값에게 몸을 구현
  4. 피를 반환하며 컴파일 시간 오류가 발생합니다 대안
  5. 없음

가장 좋은 대답은 왜 이것이 VTABLE에 기반하여 발생하는지 설명하는 것입니다. 하나의 해결책을 제시하고 이유를 설명하십시오. 아이디어는 의견을 근거로하지 않는 것입니다.

+0

이 예는 충돌하지 않습니까? 어떤 것을 보여줘. 편집 : 오, 오, 내 않습니다. 나는 당황 스럽다. –

+0

"최고의 솔루션"이란 무엇입니까? –

+0

@ PeterSchneider - 적어도 여기 있습니다. –

답변

2

기본 클래스 이 기능을 구현합니까? 단지 잘못 구현 한 것입니다. 그것은 vtables 또는 정교한 것과 관련이 없습니다. 해결책 4가 바람직하지 않은 경우 (잘못된 프로그램 작성을 방지하기 때문에), 순서대로 1 또는 2를 원하는/불가능한 경우.

오류가 전혀 가상 함수 또는 상속과 관련이 없음을주의하십시오 (Bar을 사용하지 않았습니까?). 그것은 클래스와 전혀 관련이 없지만 독립 실행 형 함수에서도 발생합니다. 고려하십시오 :

#include <iostream> 
#include <string> 

// Note: UB -- nothing returned 
int getInt() {} 
std::string getStr() {} 

int main(int argc, char ** argv) 
{ 
    // This probably works (read access from an arbitrary 
    // location on the stack which is in the prog's address space) 
    std::cout << getInt() << std::endl; 

    // This will crash. operator<< will try to access memory through 
    // a pointer value which is some arbitrary byte pattern on the stack. 
    // Probably not in the prog's address space. 
    // Then the destructor for the temporary string will 
    // try to delete the same 
    // memory which will crash in any case, even if it happens to 
    // point to valid memory (which, alas, was never allocated). 
    std::cout << getStr(); 

    std::cout << "Still alive?\n"; // never printed 
    std::cout.flush(); 

    return 0; 
} 

원본 코드에서 오류가 발생하지 않도록하려면 값을 반환하십시오. 당신이 돌아 오면 당신이 기능을 구현하고, (세 가지 대안있는) 즉를 던지거나 중단하지 않으면, 당신은 값을 반환해야합니다

#include <iostream> 

class Foo 
{ 
public: 
    virtual std::string myString() { return "test\n";} 
}; 

class Bar : public Foo 
{ 
public: 
}; 

int main(int argc, char ** argv) 
{ 
    Foo * bar = new Foo(); 
    std::cout << bar->myString(); 

    return 0; 
} 
+0

왜 기본값을 반환하겠습니까? 다른 방법으로 "해결"할 수 있습니다. –

+1

@ SH.0x90 vtable은 오늘날의 컴파일러의 다형성 구현의 고전입니다. C++에 따르면, 이것은 구현에 따라 다릅니다. vtable을 전혀 사용하지 않는 또 다른 기술을 개발할 수있는 컴파일러가있을 수 있습니다. –

+0

글쎄, 당신이 그것을 구현하는 경우, 당신은 값을 반환하거나 던지거나 중단해야합니다. 방금 호출자가 예상 한 문자열이 없기 때문에 충돌이 발생했음을 보여주고 싶었습니다. –

0

귀하의 mystring 함수는 문자열을 반환해야합니다.

+0

왜 기본값을 반환하겠습니까? 다른 방법으로 "해결"할 수 있습니다. –

+0

어떤 방식으로 작동 시키시겠습니까? 다른 값을 반환 할 수 있습니다.이 함수는 다른 함수와 같은 것을 호출 할 수 있습니다. 당신이 묻는 VTABLE은 완전히 다른 것입니다. VTABLE 조회는 기본 클래스 가상 함수의 멤버 함수를 선언 할 때 파생 클래스의 포인터가 기본 클래스에 할당 된 메모리로 만들어지면 부모 클래스를 조사합니다. –

+0

순수한 가상의 기본 클래스를 원한다. 왜냐하면 그 인스턴스를 원한다. 다른 클래스는 그 클래스에서 확장되고 기본의 모든 메소드를 구현하지 않기 때문에, 우연히 누군가가 메소드를 호출 할 수있다. 구현되지 않았고 기본 장치를 호출해야했습니다. –

1

VTABLE은 가상 메소드에 대한 포인터의 테이블입니다. 일반적으로 VTABLE에 대한 포인터는 숨겨져 있지만 클래스의 인스턴스에서 첫 번째 요소로 구현되는 경우가 많습니다.

파생 클래스에 부모 클래스가 가상으로 구현하는 멤버 함수가 없으면 부모 메서드가 호출됩니다.

관련 문제