2013-11-13 4 views
5

это первый раз, когда я сделал что-то подобное, поэтому я немного уверен, как мне это нужно. У меня есть очень простой класс, который содержит некоторые простые значения и некоторые методы получения:Возвращая указатель на класс внутри класса

class Nucleotide{ 
    private: 
     char Base; 
     int Position; 
     int Polymorphic; 
    public: 
     Nucleotide(char ch, int pos); 
     int getPos(); 
     char getBase(); 
     int getPoly(); 
}; 

Этот класс присутствует в другом классе, который содержит вектор из них:

class NucleotideSequence{ 
    private: 
     std::string Name; 
     std::vector<Nucleotide> Sequence; 
    public: 
     NucleotideSequence(std::string name, std::vector<Nucleotide> seq); 
     std::string getName(); 
     Nucleotide getBase(int pos1); 
}; 

Я хочу, чтобы метод второго класс, называемый getBase, чтобы иметь возможность взять целое число - скажем 1 и вернуть первый нуклеотидный объект в вектор. То, что я написал ниже:

Nucleotide NucleotideSequence::getBase(int pos1) 
{ 
    for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++) 
    { 
     if(pos1 == (*i).getPos()) 
     { 
      return i; // Return a pointer to the correct base. 
     } 
    } 
} 

Я получил нуклеотид в виде возвращаемого типа, но мне было интересно, на самом деле, как я должен изменить это - так, если я вернусь нуклеотид из-за проход по значению будет не только возврат копия объекта в этом месте в векторе? Поэтому я бы скорее вернул указатель/ссылку. Я использую итератор в цикле, так что я должен просто вернуть указатель со значением итератора? Как мне это сделать? В функции я возвращаю i, но должен ли я возвращать i &? Я не уверен в специфике - предположительно, если я возвращаю указатель, мой тип возврата должен быть нуклеотидом * или, возможно, нуклеотидом &, так как & означает адрес? Я думал об этом и читал Cpp, но я все еще не уверен в правильном ответе.

Thanks, Ben.

+0

Не можете просто использовать 'Sequence [Pos1]' в некотором роде? – Bernhard

ответ

5

Вы должны вернуть нуклеотид, по ссылке:.

Nucleotide & NucleotideSequence::getBase(int pos1) 
{ 
    for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++) 
    { 
     if(pos1 == (*i).getPos()) 
     { 
      return *i; // Notice the *i instead of i 
     } 
    } 
} 

ссылка работает очень похоже на указатель (позволяет передавать реальный объект, а не его копия), но не может быть пустым и не может указывать на несуществующий объект, так что это намного безопаснее, чем указатель.

Обратите внимание, что если вы не найдете нужный Nucleotide, вы ничего не вернете, что вообще не очень хорошая идея. В этом случае с помощью указателей на самом деле может быть лучшей идеей:

Nucleotide * NucleotideSequence::getBase(int pos1) 
{ 
    for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++) 
    { 
     if(pos1 == (*i).getPos()) 
     { 
      return &(*i); 
     } 
    } 

    return nullptr; 
} 
1

Вы не возвращаете указатель, вы пытаетесь вернуть итератор. И функция объявляется для возврата экземпляра, а не указателя. Кроме того, если вы не найдете Nucleotide, вы ничего не вернете, что приведет к неопределенному поведению, если вы попытаетесь использовать «возвращенное» значение.

Вы могли изменить функцию, чтобы вернуть указатель или ссылку, или просто по значению (копирование, как это декларируется как нет.

Вы также можете изменить так, что функция принимает Nucleotide как аргумент вместо этого, а затем возвращает булев индикатор, если он был найден или не

bool NucleotideSequence::getBase(int pos1, Nucleotide& n) 
{ 
    for (...) 
    { 
     if (...) 
     { 
      n = *i; 
      return true; 
     } 
    } 
    return false; // Not found 
} 
+0

Недостатком вашей души является то, что вам действительно нужен существующий нуклеотид, чтобы перейти к этой функции. Я думал об этом решении, и в этом случае использование C# -типа 'Nucleotyde :: Empty' было бы полезным, но могло бы усложнить ситуацию. – Spook

+0

@Spook Конечно. Основной недостаток заключается в том, что невозможно связать вызов (т. Е. Использовать функцию как часть выражения). Хотя это не рекомендуется при возвращении указателя, поэтому в этом случае я не вижу большой разницы. –

0

Что касается вашего вопроса, то, возвращает ссылку (&), как предложено другими является решением.

Для того, чтобы улучшить свой код, я бы так же предложить изменение:

Либо пойти для оператора [], или использовать в(), присутствующую в станд :: вектор.

Таким образом, вы можете сразу сказать:

обратной последовательности [Pos1]; или return Sequence.at (pos1);

+1

Это скорее комментарий, чем ответ, но очень правильный. – CompuChip

+0

не совсем, потому что метод getPos() не коррелирует с положением нуклеотида в последовательности. – SirDarius

+0

@CompuChip Мне до сих пор не разрешено оставлять комментарии к вопросу, поэтому он должен был опубликовать его здесь. – CinCout

0

Ваш код будет полезен при использовании ссылок на эффективность. getBase метода подпись должна выглядеть следующим образом:

const Nucleotide& NucleotideSequence::getBase(int pos1) 

NucleotideSequence конструктор подпись должна выглядеть следующим образом:

NucleotideSequence(const std::string& name, const std::vector<Nucleotide>& seq); 

И в getName метод, как это:

const std::string& getName(); 

(Хотя return value optimisation мощи сделать это менее важным.)

Что касается содержания getBase, это может помочь понять, чтобы сломать код в:

const Nucleotide* NucleotideSequence::getBase(int pos1) 
{ 
    for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); ++i) 
    { 
     Nucleotide& ref = *i; //Get a reference to the object this iterator points to 
     if(pos1 == ref.getPos()) //compare its base to the argument 
     { 
      return &ref; // Return a pointer to the correct object. 
     } 
    } 
    return NULL; //or null if we didn't find the object we wanted 
} 
Смежные вопросы