C ++方法返回指向抽象类的指针,需要使用子类中的方法

时间:2014-09-24 21:29:51

标签: c++ compiler-construction abstract-class

所以我用C ++编写了一个编译器。目前在扫描仪部分。

扫描仪内的方法声明是

Token * Scanner::next_token()
{
  string * test = new string("Test");
  IdToken * testToken = new IdToken(test);
  return testToken;  
}

IdToken类有一个方法get_attribute(),它返回私有变量attr的值(在本例中是一个字符串,在创建时传入的字符串)。令牌(抽象类)没有这种方法。

在测试的主要内容中,我有这个:

IdToken * testToken = testScanner->next_token();

但是g ++并不喜欢这样,并说这是从Token *到IdToken *的无效转换。

我需要将方法返回的标记转换为IdToken以获取属性,因为当我尝试直接调用返回的标记上的get_attribute()时,它告诉我Token :: get_attribute()不存在

我不确定如何解决这个问题,因为我对C ++继承的了解正在挣扎。我做了所有可能的研究,但我找不到任何我理解的东西并解决了我的问题。

这是Scanner.cc

Scanner::Scanner (char * filename)
{
  buf = new Buffer(filename);
}

//Destroy new things
Scanner::~Scanner()
{
  delete buf;
}

//The huge DFA turned into code
Token * Scanner::next_token()
{
  string * test = new string("Test");
  IdToken * testToken = new IdToken(test);
  return testToken;
}

这是IdToken.cc

IdToken::IdToken() : Token()
{
  set_token_type (TOKEN_ID);
  attribute = new string("UNINITIALIZED IDENTIFIER ATTRIBUTE");
}

IdToken::IdToken (string *attr) : Token()
{
  set_token_type (TOKEN_ID);
  attribute = new string(*attr);
}

IdToken::~IdToken()
{  if (attribute != NULL) {
    delete attribute;
  }
}


string *IdToken::get_attribute() const
{
  string *attr = new string(*attribute);
  return attr;
}


void IdToken::set_attribute(string *attr)
{ 
  if (attribute != NULL) {
    delete attribute;
  }
  attribute = new string (*attr);
}


string *IdToken::to_string()
{
  string *attribute_name = new string ("ID:" + *attribute);
  return attribute_name;
}    

最后是token.cc

#include "token.h"

Token::Token()
{
  type = TOKEN_NO_TYPE;
}

Token::~Token()
{}

void Token::set_token_type (token_type_type type)
{
  this->type = type;
}

token_type_type Token::get_token_type() const
{
  return type;
}

它还没有完成,我只需要帮助找出如何访问get_attribute。

3 个答案:

答案 0 :(得分:1)

几个选项:

  1. virtual中创建Token成员函数。

    virtual std::string get_attribute() const = 0;
    

    适当地实施Token的子类。用它作为:

    Token * testToken = testScanner->next_token();
    std::string attr = testToken->get_attribute();
    
  2. 使用dynamic_castIdToken*获取Token*。如果演员表演成功,请致电get_attribute()。在IdToken*

    Token * testToken = testScanner->next_token();
    IdToken * testIdToken = dynamic_cast<IdToken*>(testToken);
    if ( testIdToken )
    {
       std::string attr = testIdToken->get_attribute();
    }
    

答案 1 :(得分:0)

您可以使用dynamic_cast

struct Token {
    virtual ~Token() {} 
};

struct IdToken : public Token {
    int getAttribute() {return 1;}
};

int main(int argc, char** argv} {

    Token* token = new IdToken();

    dynamic_cast<IdToken*>(token)->getAttribute();

    delete token;
}

不幸的是,dynamic_cast往往相当慢,您可能希望避免频繁调用它。然而,它是安全的。失败时返回nullptr。您也可以使用reinterpret_cast,这更快,但不安全。

答案 2 :(得分:0)

我个人不会为代币制作类层次结构。有一组相对较小的属性和参数,如果你真的需要,你可以使用一个联合来存储它们。

但如果必须,请使用dynamic_cast来致电get_attribute

Token* token = testScanner->next_token()

IdToken *idToken = dynamic_cast<IdToken*>(token);
if(idToken)
{
   idToken->get_attribute();
}

请注意,您确实需要if,否则如果您获得的令牌不是IdToken [或来自IdToken],您的程序就会崩溃。

哦,dynamic_cast并不是一个简单的操作,根本不需要时间。因此,避免它优先于基类虚函数几乎总是更好。对于来自解析器的AST,我的编译器使用了几十个llvm::dyn_cast,因为做了一个完全通用的AST类,它可以处理变量表达式,for循环和函数声明的所有特殊情况。同一个类会产生一个具有几十个虚函数的类的怪物,其中大部分都需要单个实现一个派生类,但是一个&#34; null&#34;大多数其他人的价值 - 大部分时间我都需要知道它实际上是什么类......

这里是我的Token class - 我确定那里也有错误,我不是编译专家,这是我的第三语言,我已经参与过,并且第一个实际编译为机器代码,并且我使用llvm作为后端作弊。

不要string *something = new string;使用空的或未知的&#34;字符串表示&#34;尚未设置&#34;

也不要使用if (pointer) delete pointer; - deleteNULL的指针上工作正常 - 如果编译器可能没有删除冗余的话,因为它很小调用delete的额外开销是值得保存的 - 但不是在析构函数中。如果你在一个大型项目中到处都有一个额外的if (pointer),它很快就会增加几千字节的额外代码 - 如果析构函数恰好是内联的,那么它会乘以它所拥有的内联数量,在你的项目中可能会有很多无用的代码。编译器代码往往变得足够大而没有无用的膨胀。