繁体   English   中英

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

[英]C++ method returns pointer to abstract class, need to use a method from the subclass

所以我正在用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。

几个选择:

  1. Token创建一个virtual成员函数。

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

    Token的子类适当实现。 用作:

     Token * testToken = testScanner->next_token(); std::string attr = testToken->get_attribute(); 
  2. 使用dynamic_castToken*获取IdToken* Token* 如果转换成功,则调用get_attribute() IdToken*

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

您可以使用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 ,它速度更快,但并不安全。

我个人不会为令牌创建类层次结构。 相对而言,属性和参数的设置相对较小,如果确实需要,可以潜在地使用联合来存储它们。

但是,如果必须,请使用dynamic_cast调用get_attribute

Token* token = testScanner->next_token()

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

请注意,您确实需要if ,否则,如果您获得的令牌不是IdToken [或从IdToken派生], if程序将崩溃。

哦,而且dynamic_cast并不是一件耗时的琐碎操作。 因此,优先选择避免使用基类虚函数几乎总是更好的选择。 我的编译器对解析器中生成的AST使用了几十个llvm::dyn_cast ,因为这样做是一个完全通用的AST类,可以处理同一个变量表达式,for循环和函数声明的所有特殊情况类将使具有几十个虚函数的类变成怪物,其中大多数将需要为单个派生类实现单个实现,而对于大多数其他类则需要“空”值-并且大多数时候我需要知道它实际上是什么课...

这是我的Token类 -我确定那里也存在错误,我不是编译专家,这是我研究的第三种语言,也是第一种实际编译为机器代码的语言,我在作弊通过使用llvm作为后端。

不要做string *something = new string; 使用空字符串或“未知”字符串表示“尚未设置”

也不要使用if (pointer) delete pointer; - delete那些作品上的指针就好NULL -在一个微乎其微许多情况下,多余的,如果可能不是由编译器移除,因为,调用的额外开销delete是值得保存-但不是在析构函数。 如果您在大型项目中的每个地方都有一个附加的if (pointer) ,它很快就会增加数千字节的额外代码-如果析构函数随后被内联,则将其乘以它的内联数量,这可能是相当大的。您的项目中有很多无用的代码。 编译器代码趋向于足够大而不会造成不必要的膨胀。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM