2009-03-31 7 views
-1

분명히 'grok'하지 않습니다. C++.순수 가상 함수 호출

이 프로그래밍 할당에서 나는 막 다른 골목에 섰습니다. 이 오류 코드 줄에서 런타임 오류가 발생합니다. "런타임 오류 - 순수 가상 함수 호출"메시지와 함께

자식 클래스가 현재 인스턴스화되지 않은 동안 함수 참조가 (가상) 기본 클래스를 호출하려고하면이 오류가 발생합니다. 그러나 나는 내가이 실수를 한 곳을 보지 못했다.

관련 코드 :
교수의 코드 :

내 코드
const int LION = 1; 
const int WILDEBEEST = 2; 

// 
// . 
// . 
// . 
// 

class Animal { 
    friend class Savanna; // Allow savanna to affect animal 
public: 
    Animal(); 
    Animal(Savanna *, int, int); 
    ~Animal(); 
    virtual void breed() = 0; // Breeding implementation 
    virtual void move() = 0;  // Move the animal, with appropriate behavior 
    virtual int getType() = 0; // Return if wildebeest or lion 
    virtual bool starve() = 0; // Determine if animal starves 
protected: 
    int x,y;  // Position in the savanna, using the XY coordinate plane 
    bool moved;  // Bool to indicate if moved this turn 
    int breedTicks; // Number of ticks since breeding 
    Savanna *savanna; 
}; 

// 
// . 
// . 
// . 
// 

void Savanna::Display() 
{ 
int i,j; 

cout << endl << endl; 
for (j=0; j<SAVANNASIZE; j++) 
{ 
    for (i=0; i<SAVANNASIZE; i++) 
    { 
    if (grid[i][j]==NULL){ 
    setrgb(0); 
    cout << " "; 
    } 
    else if (grid[i][j]->getType()==WILDEBEEST) // RUNTIME ERROR HERE 
    { 
    setrgb(7); 
    cout << "W"; 
    } 
    else { 
     setrgb(3); 
     cout << "L"; 
    } 
    } 

    cout << endl; 
} 
setrgb(0); 
} 

: 나는 The Old New Thing: What is __purecall?Description of the R6025 run-time error in Visual C++을 읽었습니다하지만 난 완전히 이해하지

class Wildebeest: public Animal { 

friend class Savanna; // Allow the Savanna to affect the animal, as per spec 
public: 
    Wildebeest(); 
    Wildebeest(Savanna *, int, int); // accepts (pointer to a Savanna instance, X Position, Y Position) 
    void breed();   // Perform breeding, and check breedTick 
    void move();   // move the animal. 
    int getType();    // returns WILDEBEEST 
    bool starve();     // if starving, returns 0. (counterintuitive, I know.) 
}; 

int Wildebeest::getType() { 

    return WILDEBEEST; 
} 

는 이유는 위의 코드에서 발생 .

[편집]을 main.c의 전체 목록 (예, 모두 하나 개의 파일 ... 할당 요구 사항의 일부입니다.)

// 
// This program simulates a 2D world with predators and prey. 
// The predators (lions) and prey (wildebeest) inherit from the 
// Animal class that keeps track of basic information about each 
// animal (time ticks since last bred, position on the savanna). 
// 
// The 2D world is implemented as a separate class, Savanna, 
// that contains a 2D array of pointers to type Animal. 
// 

// **************************************************************** 

#include <iostream> 
#include <string> 
#include <vector> 
#include <cstdlib> 
#include <time.h> 
#include "graphics.h" 

using namespace std; 

int wrapTo20 (int value) { 

    if (0 > value) { 

     value = 19; 
    } else if (20 == value) { 

     value = 0; 
    } 

    return value; 
} 

const int SAVANNASIZE = 20; 
const int INITIALBEEST = 100; 
const int INITIALLIONS = 5; 
const int LION = 1; 
const int WILDEBEEST = 2; 
const int BEESTBREED = 3; 
const int LIONBREED = 8; 
const int LIONSTARVE = 3; 

// Forward declaration of Animal classes so we can reference it 
// in the Savanna class 
class Animal; 
class Lion; 
class Wildebeest; 

// ========================================== 
// The Savana class stores data about the savanna by creating a 
// SAVANNASIZE by SAVANNASIZE array of type Animal. 
// NULL indicates an empty spot, otherwise a valid object 
// indicates an wildebeest or lion. To determine which, 
// invoke the virtual function getType of Animal that should return 
// WILDEBEEST if the class is of type Wildebeest, and Lion otherwise. 
// ========================================== 

class Savanna 
{ 
friend class Animal; // Allow Animal to access grid 
friend class Lion; // Allow Animal to access grid 
friend class Wildebeest; // Allow Animal to access grid 
public: 
Savanna(); 
~Savanna(); 
Animal* getAt(int, int); 
    void setAt(int, int, Animal *); 
void Display(); 
void SimulateOneStep(); 
private: 
Animal* grid[SAVANNASIZE][SAVANNASIZE]; 
}; 


// ========================================== 
// Definition for the Animal base class. 
// Each animal has a reference back to 
// the Savanna object so it can move itself 
// about in the savanna. 
// ========================================== 
class Animal 
{ 
friend class Savanna; // Allow savanna to affect animal 
public: 
Animal(); 
Animal(Savanna *, int, int); 
~Animal(); 
virtual void breed() = 0; // Whether or not to breed 
virtual void move() = 0; // Rules to move the animal 
virtual int getType() = 0; // Return if wildebeest or lion 
virtual bool starve() = 0; // Determine if animal starves 
protected: 
int x,y; // Position in the savanna 
bool moved; // Bool to indicate if moved this turn 
int breedTicks; // Number of ticks since breeding 
Savanna *savanna; 
}; 

// ====================== 
// Savanna constructor, destructor 
// These classes initialize the array and 
// releases any classes created when destroyed. 
// ====================== 
Savanna::Savanna() 
{ 
// Initialize savanna to empty spaces 
int i,j; 
for (i=0; i<SAVANNASIZE; i++) 
{ 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    grid[i][j]=NULL; 
    } 
} 
} 

Savanna::~Savanna() 
{ 
// Release any allocated memory 
int i,j; 
for (i=0; i<SAVANNASIZE; i++) 
{ 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    if (grid[i][j]!=NULL) delete (grid[i][j]); 
    } 
} 
} 

// ====================== 
// getAt 
// Returns the entry stored in the grid array at x,y 
// ====================== 
Animal* Savanna::getAt(int x, int y) 
{ 
if ((x>=0) && (x<SAVANNASIZE) && (y>=0) && (y<SAVANNASIZE)) 
    return grid[x][y]; 
return NULL; 
} 

// ====================== 
// setAt 
// Sets the entry at x,y to the 
// value passed in. Assumes that 
// someone else is keeping track of 
// references in case we overwrite something 
// that is not NULL (so we don't have a memory leak) 
// ====================== 
void Savanna::setAt(int x, int y, Animal *anim) 
{ 
if ((x>=0) && (x<SAVANNASIZE) && (y>=0) && (y<SAVANNASIZE)) 
{ 
    grid[x][y] = anim; 
} 
} 

// ====================== 
// Display 
// Displays the savanna in ASCII. Uses W for wildebeest, L for lion. 
// ====================== 
void Savanna::Display() 
{ 
int i,j; 

cout << endl << endl; 
for (j=0; j<SAVANNASIZE; j++) 
{ 
    for (i=0; i<SAVANNASIZE; i++) 
    { 
    if (grid[i][j]==NULL){ 
    setrgb(0); 
    cout << " "; 
    } 
    else if (grid[i][j]->getType()==WILDEBEEST) 
    { 
    setrgb(7); 
    cout << "W"; 
    } 
    else { 
     setrgb(3); 
     cout << "L"; 
    } 
    } 

    cout << endl; 
} 
setrgb(0); 
} 

// ====================== 
// SimulateOneStep 
// This is the main routine that simulates one turn in the savanna. 
// First, a flag for each animal is used to indicate if it has moved. 
// This is because we iterate through the grid starting from the top 
// looking for an animal to move . If one moves down, we don't want 
// to move it again when we reach it. 
// First move lions, then wildebeest, and if they are still alive then 
// we breed them. 
// ====================== 
void Savanna::SimulateOneStep() 
{ 
int i,j; 
// First reset all animals to not moved 
for (i=0; i<SAVANNASIZE; i++) 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    if (grid[i][j]!=NULL) grid[i][j]->moved = false; 
    } 
// Loop through cells in order and move if it's a Lion 
for (i=0; i<SAVANNASIZE; i++) 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    if ((grid[i][j]!=NULL) && (grid[i][j]->getType()==LION)) 
    { 
    if (grid[i][j]->moved == false) 
    { 
    grid[i][j]->moved = true; // Mark as moved 
    grid[i][j]->move(); 
    } 
    } 
    } 
// Loop through cells in order and move if it's an Wildebeest 
for (i=0; i<SAVANNASIZE; i++) 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    if ((grid[i][j]!=NULL) && (grid[i][j]->getType()==WILDEBEEST)) 
    { 
    if (grid[i][j]->moved == false) 
    { 
    grid[i][j]->moved = true; // Mark as moved 
    grid[i][j]->move(); 
    } 
    } 
    } 
// Loop through cells in order and check if we should breed 
for (i=0; i<SAVANNASIZE; i++) 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
     // Kill off any lions that haven't eaten recently 
    if ((grid[i][j]!=NULL) && 
     (grid[i][j]->getType()==LION)) 
    { 
    if (grid[i][j]->starve()) 
    { 
    delete (grid[i][j]); 
    grid[i][j] = NULL; 
    } 
    } 
    } 
// Loop through cells in order and check if we should breed 
for (i=0; i<SAVANNASIZE; i++) 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
    // Only breed animals that have moved, since 
    // breeding places new animals on the map we 
    // don't want to try and breed those 
    if ((grid[i][j]!=NULL) && (grid[i][j]->moved==true)) 
    { 
    grid[i][j]->breed(); 
    } 
    } 
} 

// ====================== 
// Animal Constructor 
// Sets a reference back to the Savanna object. 
// ====================== 
Animal::Animal() 
{ 
savanna = NULL; 
moved = false; 
breedTicks = 0; 
x=0; 
y=0; 
} 

Animal::Animal(Savanna *savana, int x, int y) 
{ 
this->savanna = savana; 
moved = false; 
breedTicks = 0; 
this->x=x; 
this->y=y; 
savanna->setAt(x,y,this); 
} 

// ====================== 
// Animal destructor 
// No need to delete the savanna reference, 
// it will be destroyed elsewhere. 
// ====================== 
Animal::~Animal() 
{ } 

// Start with the Wildebeest class and its required declarations 
class Wildebeest: public Animal { 

    friend class Savanna; // Allow savanna to affect animal 
public: 
    Wildebeest(); 
    Wildebeest(Savanna *, int, int); 
void breed();   // Whether or not to breed 
void move();   // Rules to move the animal 
int getType();   // Return if wildebeest or lion 
bool starve(); 
}; 

bool Wildebeest::starve() { 

    return 1; 
} 


// ====================== 
// Wildebeest constructors 
// ====================== 

Wildebeest::Wildebeest() { 

} 

Wildebeest::Wildebeest(Savanna * sav, int x, int y) : Animal(sav, x, y) { 

} 

// ====================== 
// Wldebeest Move 
// Look for an empty cell up, right, left, or down and 
// try to move there. 
// ====================== 

void Wildebeest::move() { 

    int loc1, loc2, loc3, loc4; 
    int x1, x2, x3, x4; 
    int y1, y2, y3, y4; 

    x1 = wrapTo20(x); 
    y1 = wrapTo20(y + 1); 

    x2 = wrapTo20(x + 1); 
    y2 = wrapTo20(y); 

    x3 = wrapTo20(x); 
    y3 = wrapTo20(y - 1); 

    x4 = wrapTo20(x - 1); 
    y4 = wrapTo20(y); 

    loc1 = savanna->getAt(x1, y1)->getType(); 
    loc2 = (int)savanna->getAt(x2, y2)->getType(); 
    loc3 = savanna->getAt(x3, y3)->getType(); 
    loc4 = savanna->getAt(x4, y4)->getType(); 

    while (!moved) { 
     int x = 1 + (rand() % 4); 
     switch (x) { 

      case 1: 
       if (!loc1) savanna->setAt(x1, y1, this); 
       break; 

      case 2: 
       if (!loc2) savanna->setAt(x2, y2, this); 
       break; 

      case 3: 
       if (!loc3) savanna->setAt(x3, y3, this); 
       break; 

      case 4: 
       if (!loc4) savanna->setAt(x4, y4, this); 
       break; 

      default: 
       break; 
     } 
    } 
} 



// ====================== 
// Wildebeest getType 
// This virtual function is used so we can determine 
// what type of animal we are dealing with. 
// ====================== 
int Wildebeest::getType() { 

    return WILDEBEEST; 
} 

// ====================== 
// Wildebeest breed 
// Increment the tick count for breeding. 
// If it equals our threshold, then clone this wildebeest either 
// above, right, left, or below the current one. 
// ====================== 

void Wildebeest::breed() { 
    breedTicks++; 

    if (2 == breedTicks) { 
     breedTicks = 0; 
    } 

} 

// ***************************************************** 
// Now define Lion Class and its required declarations 
// ***************************************************** 

class Lion: public Animal { 

    friend class Savanna; // Allow savanna to affect animal 
public: 
    Lion(); 
    Lion(Savanna *, int, int); 
void breed();   // Whether or not to breed 
void move();   // Rules to move the animal 
int getType();   // Return if wildebeest or lion 
bool starve(); 
}; 


// ====================== 
// Lion constructors 
// ====================== 

Lion::Lion() { 

} 

Lion::Lion(Savanna * sav, int x, int y) : Animal(sav, x, y) { 

} 


// ====================== 
// Lion move 
// Look up, down, left or right for a lion. If one is found, move there 
// and eat it, resetting the starveTicks counter. 
// ====================== 

void Lion::move() { 

    int loc1, loc2, loc3, loc4; 
    int x1, x2, x3, x4; 
    int y1, y2, y3, y4; 

    x1 = wrapTo20(x); 
    y1 = wrapTo20(y + 1); 

    x2 = wrapTo20(x + 1); 
    y2 = wrapTo20(y); 

    x3 = wrapTo20(x); 
    y3 = wrapTo20(y - 1); 

    x4 = wrapTo20(x - 1); 
    y4 = wrapTo20(y); 

    loc1 = savanna->getAt(x1, y1)->getType(); 
    loc2 = (int)savanna->getAt(x2, y2)->getType(); 
    loc3 = savanna->getAt(x3, y3)->getType(); 
    loc4 = savanna->getAt(x4, y4)->getType(); 

    while (!moved) { 
     int x = 1 + (rand() % 4); 
     switch (x) { 

      case 1: 
       if (!loc1) savanna->setAt(x1, y1, this); 
       break; 

      case 2: 
       if (!loc2) savanna->setAt(x2, y2, this); 
       break; 

      case 3: 
       if (!loc3) savanna->setAt(x3, y3, this); 
       break; 

      case 4: 
       if (!loc4) savanna->setAt(x4, y4, this); 
       break; 

      default: 
       break; 
     } 
    } 
} 

// ====================== 
// Lion getType 
// This virtual function is used so we can determine 
// what type of animal we are dealing with. 
// ====================== 

int Lion::getType() { 

    return LION; 
} 

// ====================== 
// Lion breed 
// Creates a new lion adjacent to the current cell 
// if the breedTicks meets the threshold. 
// ====================== 

void Lion::breed() { 

    breedTicks++; 

    if (2 == breedTicks) { 
     breedTicks = 0; 
    } 

} 


// ====================== 
// Lion starve 
// Returns true or false if a lion should die off 
// because it hasn't eaten enough food. 
// ====================== 


bool Lion::starve() { 

    return 1; 
} 


// ====================== 
//  main function 
// ====================== 
int main() 
{ 
    string s; 
    srand((int)time(NULL)); // Seed random number generator 
    Savanna w; 
    int initialWildebeest=0; 
    int initialLions=0; 

    // enter initial number of wildebeest 
    int beestcount = 0; 
    while(initialWildebeest <= 0 || initialWildebeest > INITIALBEEST){ 
    cout << "Enter number of initial Wildebeest (greater than 0 and less than " << INITIALBEEST << ") : "; 
    cin >> initialWildebeest; 
    } 
    // Randomly create wildebeests and place them in a randomly choosen empty spot in savanna 


    int i; 
    bool placed = 0; 

    for (i = 0; i < initialWildebeest; i++) { 
     while (!placed) { 
      int x = 1 + (rand() % 20); 
      int y = 1 + (rand() % 20); 

      if (!(w.getAt(x, y))){ 
       Wildebeest fred(&w, x, y); 
       placed = 1; 
      } 
     } 
     placed = 0; 
    } 


    // Enter initial number of lions 
    int lioncount = 0; 
    while(initialLions <= 0 || initialLions > INITIALLIONS){ 
    cout << "Enter number of initial Lions (greater than 0 and less than " << INITIALLIONS << ") : "; 
    cin >> initialLions; 
    } 
    // Randomly create lions and place them in a randomly choosen empty spot in savanna 

    placed = 0; 

    for (i = 0; i < initialLions; i++) { 
     while (!placed) { 
      int x = 1 + (rand() % 20); 
      int y = 1 + (rand() % 20); 

      if (!(w.getAt(x, y))){ 
       Lion ronald(&w, x, y); 
       placed = 1; 
      } 
     } 
     placed = 0; 
    } 

    // Run simulation forever, until user cancels 
    int count=0; 
    while (true) 
    { 
    gotoxy(0,0); 
    w.Display(); 
    w.SimulateOneStep(); 
    Sleep(500); 
    count++; 
    if(count == 20){ 
    count=0; 
    cout << endl << "Press enter for next step, ctrl-c to quit" << endl; 
    getline(cin,s); 
    clearline(23); 

    } 
    } 
    return 0; 
} 
+0

그리드의 정의를 제공 할 수 있습니까? – Uri

답변

10

grid의 정의는 무엇이며 어떻게 채우고 있습니까? 나는 당신이 Animal 생성자로부터 그것을하고 있다고 확신한다. 현재이 동적 유형은 Animal이며 최종적으로 생성되는 객체의 유형이 아닙니다. 객체가 완전히 구성 될 때까지

Animal::Animal() 
{ 
    grid[i][j] = this; // the type of this is Animal 
} 

, 당신이 가상 함수를 호출하거나, 가상 함수 테이블을 사용하여 포함, 동적 인 방법으로 this 포인터를 사용할 수 없습니다.

더 구체적으로는 this 포인터를 사용하여 연기합니다. 즉, 개체가 완전히 구성 될 때까지 포인터를 grid 배열에 저장해야합니다. 동물의 생성자에서 다음

: 당신이 this 매개 변수 Savanna::setAt를 호출

Animal::Animal(Savanna *savana, int x, int y) 
{ 
this->savanna = savana; 
moved = false; 
breedTicks = 0; 
this->x=x; 
this->y=y; 
savanna->setAt(x,y,this); 
} 

참고. 이 시점에서 동적 유형 this은 Wildebeest가 아닌 Animal입니다. setAt이 작업을 수행합니다 :

void Savanna::setAt(int x, int y, Animal *anim) 
{ 
if ((x>=0) && (x<SAVANNASIZE) && (y>=0) && (y<SAVANNASIZE)) 
{ 
    grid[x][y] = anim; 
} 
} 

anim의 값은 동물의 생성자에서이 포인터이다.

몇 가지 유의 사항.당신이에서 Wildebeest의 목록을 구성 할 때, 당신은 매달려 포인터를 일으키는 :

for (i = 0; i < initialWildebeest; i++) { 
    while (!placed) { 
      int x = 1 + (rand() % 20); 
      int y = 1 + (rand() % 20); 

      if (!(w.getAt(x, y))){ 
****      Wildebeest fred(&w, x, y); 
        placed = 1; 
      } 
    } 
    placed = 0; 
} 

누우은 fred이 다음 행에서 범위를 벗어나 이동하고 파괴라는. 당신은 new를 통해 동적으로 할당해야합니다

Savanna::~Savanna() 
{ 
// Release any allocated memory 
int i,j; 
for (i=0; i<SAVANNASIZE; i++) 
{ 
    for (j=0; j<SAVANNASIZE; j++) 
    { 
****  if (grid[i][j]!=NULL) delete (grid[i][j]); 
    } 
} 
} 

당신은 정확하게해야합니다 :

for (i = 0; i < initialWildebeest; i++) { 
    while (!placed) { 
      int x = 1 + (rand() % 20); 
      int y = 1 + (rand() % 20); 

      if (!(w.getAt(x, y))){ 
        Wildebeest *fred = new Wildebeest(&w, x, y); 
        placed = 1; 
      } 
    } 
    placed = 0; 
} 

을 사바나의 destrcuctor에서 일치하는 전화가 너무 삭제 우리는 메모리 누수가되지 않는 것이있다 라이온스 사례에서도 마찬가지입니다.

+0

클래스 정의에이 ctor가 포함되어 있기 때문에 생각했습니다. Animal (Savanna *, int, int); 두 개의 int가 격자 좌표입니다. –

+0

그래, 파괴에도 똑같이 적용된다는 점에 유의하십시오. – jpalecek

+0

나는 프로그램의 흐름이 다음과 같이 정확한 문제라고 생각하지 않는다 : (1) 그리드 [N] [N] 모두 Ns에 NULL을 초기화한다. (2) 그리드 [] []의 랜덤 항목을 다음과 같이 채운다. Lion 또는 Wildebeest (3.) grid [i] [j] -> getType()으로 입력 당 실패합니다. – locriani

1

글쎄, 난 격자 배열을 intializes 코드를 볼 수 없습니다 . 아마도 격자가 스택이나 힙에 만들어 졌으므로 초기화되지 않은 값으로 채워집니다. 초기화되지 않은 값은 무엇이든 될 수 있지만 NULL이 아니며 유효한 포인터가 아닙니다.

+0

null 포인터 dereferencing에서 purecall을 얻지 못할 것입니다. –

+0

포인트가 너무 적어 코드가 게시되지 않았습니다. 그리드에 무엇이 있는지 몰라도 나는 (또는 다른 누구도) 문제를 진단 할 수 있다고 생각하지 않습니다. –

+0

나는 그것을 되 찾는다. 귀하의 회신에 대한 내 의견을 참조하십시오 :-) –

-1

반드시 문제의 원인 일 필요는 없지만 코드를 너무 깊이 읽지는 ​​않았지만 가상 소멸자는 사용하지 않아야합니다.

0

순수 가상 오류 메시지는 호출되는 함수에 구현이 없다는 것을 의미합니다. 그것은 효과적으로 메소드에 대한 포인터 유형의 null 포인터를 호출합니다. (구문이 =0; 인 이유입니다.) 그래서, 다른 어떤 일이 일어나더라도, 오류 메시지는 거기에 Wildebeast가 가리키고 있지 않음을 알려줍니다.

내가 거기 아무거나 거기에 있는지 여부를 확인하기 위해 약간의 코드를 추가하는 유혹 실제 것. null에 대한 검사가 있습니다. 따라서 질문은 인 것입니까?

배열이 올바른 방법으로 초기화되지 않았 음이 거의 확실합니다.

0

당신의 문제는 순수 가상 함수 (컴파일러가 결코 런타임 오류를 일으키지 않도록 허용 할 수 없다)를 호출하는 것이 아니라 생각하는 잘못된 메모리 영역에서 함수를 호출하고 있다고 생각합니다. 잘못된 가상 테이블.

나는 동적 변수를 할당하는 대신 자동 변수로 짐승을 구성하는 방법과 관련이 있을지도 모른다. 그 ifs에서 벗어나 자마자, 그 기억은 재활용됩니다. 문제의

3

하나는

if (!(w.getAt(x, y))){ 
     Wildebeest fred(&w, x, y); 
     placed = 1; 
    } 

... 스택에에서 Wildebeest를 만들고 생성자에서 주소를 ...이 라인입니다 스택에 거주에서 Wildebeest 승의 그리드에 박제되는 , 그 때 Wildebeest는 범위를 벗어난다. 귀하의 영양 떼 라이온스가 힙에 살 필요

...

경우 (! (w.getAt (X, Y))) {

// hey maintenance programmer, this looks like I'm leaking the Wildebeest, 
    // but chillax, the Savannah is going to delete them 

    Wildebeest *fred = new Wildebeest(&w, x, y); 
    placed = 1; 

}

.. 당신이하고있는 일이 관용적 인 C++에서 멀리 떨어져 있기 때문에 주석이 필요합니다.