【问题标题】:How to call a destructor in C++如何在 C++ 中调用析构函数
【发布时间】:2020-04-10 04:15:57
【问题描述】:

我试图在这里找到答案,但我没有找到任何工作。我在这里有一个二十一点游戏。我的下一步是开始在游戏中添加资金余额和下注,但在此之前,我正在研究我的“再玩一次”选项。就目前而言,当玩家再次比赛时,他们的手牌与上一轮相同。我相信我需要调用一个析构函数来删除当前的手牌和套牌,然后重新开始。不幸的是,我无法弄清楚如何清除手牌并从新的牌组开始。我试图在我的名为 play 的函数中调用这个析构函数。在这里,如果玩家说他们想再玩一次,我会删除手牌和套牌,然后他们会在 main 中重建。但是我已经尝试了“deck.Deck::~Deck()”和“deck.~Deck()”,但都没有工作。我将上传我所有的代码。如果有人有任何想法,请帮助我。我知道析构函数应该在超出范围时由编译器调用,但是当游戏仍在运行且 main 仍在运行时,我如何从新的手牌和牌组开始呢? 感谢您的帮助。

这是我的头文件:

//blackjack.h A class to represent a deck of cards
#include <iostream>
#include <string>


class Card { 
  friend class Deck;
  private:
    int card_index; //card number 0 to 51
    Card(int index) { card_index = index; } //made this private so user can't say card at index 100..can use it because of friend class
  public:
    Card() { card_index = 52; }
    char suit() const;
    char value() const;
    std::string str() const;
    int getValue(std::string c);
};

class Deck {
  private:
    Card cards[52];
    int pos;
  public:
    Deck();
    ~Deck();
    Card deal() { return cards[pos++]; };
    void shuffle();
    int size() const { return 52 - pos; };
};

class Hand {
  friend class Deck;
  friend class Card;
  private:
    int handSize;
    int ctotal;
    Card myCards[52];

  public:   
    Hand() { handSize = 1; };
    ~Hand();
    Hand(int n) { handSize = n; };
    void dealFrom(Deck& d);
    void reveal();   
    int total();
    void hit(Deck& d);
};

std::ostream& operator<< (std::ostream& out, const Card& c);

这是我的实现文件:

//blackjack.cpp - Implementations of the Deck and Card classes
#include "blackjack.h"
#include <cstdlib>



char Card::suit() const {
  static char suits[] = { 'H', 'S', 'D', 'C' };
  //return card_index < 52 ? suits[card_index % 4] : 'X';
  return suits[card_index % 4];
}

char Card::value() const {
  static char values[] = 
    { '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' };
    //return card_index < 52 ? values[card_index / 4] : 'X';
    return values[card_index / 4];
}

std::string Card::str() const {
  std::string s;
  s += value();
  s += suit();
  return s;
}

Deck::Deck() {
  for (int i = 0; i < 52; i ++) {
    cards[i] = Card(i);
  }
  pos = 0;
}

void Deck::shuffle() {
  for (int i = 0; i < 52; i++) {
    int j = rand() % 52;
    Card tmp = cards[i];
    cards[i] = cards[j];
    cards[j] = tmp;
  }
  pos = 0;
}

std::ostream& operator<< (std::ostream& out, const Card& c) {
  out << c.str();
  return out;
}

int Card::getValue(std::string c) {
  char v = c[0];
  int val = v - '0';
  if (val > 9) {
    switch(v){
      case 'T':
      case 'J':
      case 'Q':
      case 'K':
        val = 10;
        break;
      case 'A':
         val = 11;
    }
  }
  return val;

}
void Hand::dealFrom(Deck& d) {
  for(int i = 0; i < handSize; i++)
      myCards[i] = d.deal();
}

void Hand::reveal(){ 
  for (int i = 0; i < handSize; i++) 
    std::cout << myCards[i] << " " << std::endl;
}

void Hand::hit(Deck& d) {
  int index = handSize;
  handSize++;
  myCards[index] = d.deal();

}

int Hand::total() {

  ctotal = 0; //reset card total

  for (int i = 0; i < handSize; i ++) {
    ctotal += myCards[i].getValue(myCards[i].str());
  }

  for (int i = 0; i < handSize; i ++) { //make ace 1 if over 21
    if ( (myCards[i].getValue(myCards[i].str()) == 11) && ctotal > 21 )
      ctotal = ctotal - 10;
  }

  return ctotal;

}

这是我的主程序:

#include "blackjack.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

void play(bool& quitGame, bool& quit, Deck& deck, Hand& d,Hand & p) { //function to play again?
  char ans;
  cout << "\nPlay Again? y or n" << endl;
  cin >> ans;
  if (ans == 'y' || ans == 'Y') {
    quitGame = false;
    quit = false;
    deck.Deck::~Deck(); //trying to delete the deck and hand objects before next game
    d.Hand::~Hand();
    p.Hand::~Hand();
    //deck.~Deck();
    //d.~Hand();
    //p.~Hand();

  } else if (ans == 'n' || ans == 'N')
    quitGame = true;
  else {
    cout << "Incorrect response." << endl;
    play(quitGame, quit, deck, d, p);
  }

}

void reveal(Hand& d, Hand& p) { //function to reveal the hand
  cout << "Your hand is: " << endl;
      p.reveal();
      cout << "Your total is: " << endl;
      cout << p.total() << endl;
      cout << endl;
      cout << "Dealer's hand is: " << endl;
      d.reveal();
      cout << "Dealer's total is: " << endl;
      cout << d.total() << endl;
}
void autoComplete(Hand& d, Hand& p, bool& quit, bool& quitGame, Deck& deck) { //function to check for blackjack and over 21
  if (p.total() == 21 && d.total() == 21) {
    cout << "You and dealer both hit blackjack. You tied." << endl;
    quit = true;
    play(quitGame, quit, deck, d, p);
  } else if(p.total() == 21) {
    cout << "Congratulations, you hit blackjack. You win!" << endl;
    quit = true;
    play(quitGame, quit, deck, d, p);
  } else if(d.total() == 21) {
    cout << "Sorry. Dealer hit blackjack. You lose." << endl;
    quit = true;
    play(quitGame, quit, deck, d, p);    
  } else if (p.total() > 21 && d.total() > 21) {
    cout << "You and dealer both passed 21. Game is a tie." << endl;
    quit = true;
    play(quitGame, quit, deck, d, p);
  } else if (p.total() > 21 && d.total() < 21) {
    cout << "You passed 21. You lose.";
    quit = true;
    play(quitGame, quit, deck, d, p);
  } else if (d.total() > 21 && p.total() < 21) {
    cout << "Dealer passed 21. You win.";
    quit = true;
    play(quitGame, quit, deck, d, p);
  }
}

int main() {
  srand(time(0));

  char response; // variable to hit or stand
  bool quit = false; //variable to end the current round
  bool quitGame = false; //variable to play game again

  while (quitGame == false) { //while the player wants to continue playing

    Deck deck; //create deck
    Hand p(2); //player's hand
    Hand d(2); //dealer's hand
    deck.shuffle(); //shuffle deck
    p.dealFrom(deck); //deal from deck
    d.dealFrom(deck);

    while (quit == false) { //while the round isn't over
      reveal(d, p); //reveal the cards
      autoComplete(d, p, quit, quitGame, deck); //check for blackjack and over 21


      if(p.total() < 21 && quit == false) { //if games not over and player is under 21
        cout << "Press 'h' to hit or 's' to stand." << endl;
        cin >> response; 
      }

      if (response == 'h') {
        cout << " " << endl;
        p.hit(deck);
        if (d.total() < 17) //if the dealer hasn't hit 17, dealer hits deck
          d.hit(deck);
      }
      if (response == 's') {
        cout << " " << endl;
        while (d.total() < 17){ //if the dealer hasn't hit 17, keep hitting deck
          d.hit(deck);
        }
        if (d.total() < 21 && p.total() < 21) {
          if (d.total() > p.total() && quit == false) { //if dealers total is higher than players total
            reveal(d, p);
            cout << "\nDealer wins!" << endl;
            quit = true;
            play(quitGame, quit, deck, d, p);
          } else if (p.total() > d.total() && quit == false) { //if players total is higher than dealers total
            reveal(d, p);
            cout << "\nYou win!" << endl;
            quit = true;
            play(quitGame, quit, deck, d, p);
          } else if (p.total() == d.total() && quit == false) { //if dealers total equals players total
            reveal(d, p);
            cout << "\nYou tied." << endl;
            quit = true;
            play(quitGame, quit, deck, d, p);
          }
        }
      } 
    }
  }    

  return 0;

}

【问题讨论】:

  • 你不直接调用析构函数。您是否正在尝试“重置”这些对象?如果是这样,您可以将新对象复制分配给您的变量deck = Deck();。这会破坏之前的Deck 对象,同时创建一个新对象并将其分配回deck 变量。
  • 您通常不会手动调用析构函数,除非您还使用placement new(这是您很少需要做的事情)。
  • This question & answer 可能会提供一些有用的建议。需要显式调用析构函数表明您已将自己从糟糕的设计中逼入绝境,或者您有非常具体的理由这样做。
  • 析构函数用于清理类拥有的资源,而不是重置它们。您的类没有任何需要清理的数据,因此您实际上不需要析构函数。
  • 奇怪的是“播放”实际上并没有播放(这发生在main(),老实说这是导致这个兔子洞的真正问题)。货币数据应通过引用从main() 提供到play,实际的牌组、手牌管理等都应从play 驱动。 IE。 main 应该只是控制整个程序。在play() 及其支持功能中进行任何单次发牌,包括洗牌、发牌、下注(资金由main() 提供)等。

标签: c++ destructor


【解决方案1】:

语法:

Class obj;
obj.~Class();

将调用该对象的析构函数。但是,您应该这样做。举个例子:

#include <cstdio>

class Foo {
public:
    Foo() {}
    ~Foo() {
        printf("Destroya\n");
        if (foo_m) delete foo_m;
    }
private:
    int* foo_m = new int(42);
};

int main() {
    Foo foo;
    foo.~Foo();
}

Link to code

从输出中可以看出,析构函数被调用了两次。第一次是我们手动“销毁”一个对象,然后是它实际离开堆栈时。

几乎从不手动调用析构函数。该对象不会消失,您只会破坏其状态并获得未定义的行为。您真正想要的可能是类似clear()reset() 的函数来重新初始化状态。或者按照 cmets 中的建议,您可以将分配一个默认对象移动到您已经存在的对象中以重置状态,而无需编写额外的函数。

【讨论】:

  • 不,它不是war ship,它是一个“析构函数”。仍然很有趣,通常人们会反其道而行之,从后者推导出动词“破坏”;)
  • 是的,抓住并改变了。漫画太多了。不过,保持原样打印语句。这是故意的。
  • "Never" 是一个错误的花絮,因为放置 new 可能存在异常,实际上 需要 调用析构函数。或者在其他一些极端情况下(例如,当您从容器中删除元素时,标准库可能会这样做,因为它希望独立地保持存储但必须断言对象已被销毁)。虽然仍然 +1,但总体而言答案很好。
  • 已接受,(但永远不要说永远;有instances 不仅允许手动析构函数,而且是必需)。
  • 'The object doesn't go away' – 嗯,实际上(按照标准的措辞),它确实(或者换句话说,对象不再活着),只是它的存储空间仍然存在。
【解决方案2】:

析构函数通常不是您手动调用的东西。对于堆栈上的内存,当对象超出范围时会自动调用析构函数。对于堆上的内存,使用delete 时会调用析构函数。在这种情况下,您实际上并不想删除手,您只想重置它。 deck = Deck() 将“重置”它并为您提供一个默认构造的 Deck 对象。

【讨论】:

    【解决方案3】:

    我如何 [do] 在游戏仍在进行中且主程序仍在运行时从新的手牌和牌组开始

    基本上,您只需要在一个地方调用play:在main 的内循环之外(“当一轮还没有结束”)。除了所有重复的代码之外,您的问题是当玩家想再次玩时,您将quitquitGame 都设置为false,这样内部循环就永远不会终止,您的牌组也永远不会重新洗牌。

    其他问题,留给读者作为练习:response 在被赋值之前可以被读取。您的shuffle 套路不是很好,因为很多卡片不会被移动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-28
      • 2019-06-26
      • 2018-02-06
      • 2014-05-03
      • 1970-01-01
      • 2020-11-01
      • 2018-06-02
      • 1970-01-01
      相关资源
      最近更新 更多