#c #object #constructor #static
#c #объект #конструктор #статический
Вопрос:
Итак, я пришел с Java, изучаю c . Я хочу реализовать программу, которая может быть вызвана следующим образом, предоставляемую тестовым файлом (boots):
auto subject = anagram::anagram("diaper");
auto matches = subject.matches({"hello", "world", "zombies","pants"});
vector<string> expected;
BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), matches.begin(), matches.end());
Я правильно понял, что anagram::anagram(...)
это конструктор, создающий объект, который предоставляет метод matches(...)
? Потому что в моей реализации (см. Ниже) Я получаю сообщение об ошибке, говорящее что-то (не на английском языке), например «конструктор не может быть вызван напрямую». Я думаю, что есть что-то, чего я не понимаю в конструкторах в c .
// this is part of my implementation of anagram.h
class anagram{
public:
anagram(const string a);
vector<string> matches(vector<string> amp;list);
private:
string a;
bool isAnagram(string s);
};
Единственное, что я знаю, это то, что это anagram::anagram(...)
может быть статический метод с возвращаемым значением, аналогичным this
, но для меня это не имело бы смысла. Было бы неплохо, если бы кто-нибудь мог это объяснить 🙂
Комментарии:
1.
auto subject = anagram::anagram("diaper");
недопустимый вызов конструктора.2. Это может быть фабричная функция внутри пространства имен.
3. Опечатка; Конструкторы «вызываются» как
ClassName(stuff)
илиClassName{stuff}
. Вы не квалифицируете вызов как `CalssName::className(stuff)4. хорошо, я понимаю, что это не конструктор, но и не опечатка (я почти уверен), поскольку это тестовый файл, предоставляемый веб-сайтом для онлайн-тестирования кода. Можете ли вы подробнее рассказать об этой фабричной функции?
5. @asu вы правы, я бы сам написал этот код по-другому, но поскольку это тест, мне нужно придерживаться того, что мне дано, и предоставить это бесполезное пространство имен
Ответ №1:
Поскольку вы пришли с java, вы привыкли видеть что-то похожее на это:
someobject T = new someObject(argument);
в C вы создаете класс другим способом:
someObject T(argument);
и тада вы создали объект с именем T в c . другой способ — создать указатель на объект:
someObject *T = new someObject(argument);
который больше похож на Java, но теперь вам нужно удалить этот указатель вручную. Всегда лучше создавать объекты в стеке, а не в куче. это позволяет избежать утечек памяти.
Чтобы ответить на ваш вопрос: вы ошиблись. Вы вызываете конструкторы, как я показал вам ранее. вы правы в том, как вызвать статическую memberфункцию, но это не относится к Ctor, потому что он никогда не может быть ни статическим, ни виртуальным.
Комментарии:
1. Использование кучи в ситуации, когда вы могли бы использовать стек, иногда может иметь преимущества. Однажды у меня была ситуация, когда в стеке был выделен большой массив, который работал намного хуже, чем a
std::vector
(который использует кучу внутри); вероятно, по причинам кэша. Но в общих случаях я не могу не согласиться.2. Так это на самом деле статическая функция? Но
matches
это все еще объект класса angram, верно?3. Да, но для чего бы это ни стоило, указание типа
matches
сделало бы код, скорее всего, более понятным и не намного длиннее. Это полезно, когда у вас длинные имена, например, когда вы обрабатываете итераторы, кортежи и т.д.4. @suffi Нет, это не статическая функция!!!!! Ctor не может быть статичным!!!!
5. Я бы не стал называть конструктор статической функцией, потому что это довольно неоднозначно. Выполнение
someObject(argument)
будет эффективно выделять и создаватьsomeObject
объект. Вас также может заинтересовать время жизни объекта
Ответ №2:
Если вызов anagram::anagram
должен работать anagram
с пространством имен внутри него, вызываемая функция anagram
определяется для возврата объекта, для которого вы можете вызвать метод matches
:
namespace anagram {
SomeType anagram(string n) { return SomeType(n); }
};
Это также может быть именем класса anagram
внутри пространства anagram
имен .
Это не может быть статическим методом, поскольку ни один метод, кроме ctors, не может использовать имя класса в качестве идентификатора.
Комментарии:
1. 1 вот и все, но я думаю, что @revolver_ocelot был немного быстрее, хотя сначала я не понял, что он говорил, спасибо! 🙂
Ответ №3:
Один из способов, которым он может работать с синтаксисом, который вы показали, — это если класс anagram
помещен в аналогичное именованное пространство имен:
#include <string>
namespace anagram
{
class anagram
{
public:
anagram(std::string s) {}
};
}
int main()
{
auto subject = anagram::anagram("diaper");
}
Комментарии:
1. это не имеет значения, потому что он предположил
anagram
, что конструктор может быть вызван как любой другой статический метод.2. Имеет ли смысл вообще делать что-то подобное?
3. Он просто предоставляет вам тот же синтаксис, что и тот, который вы упомянули, но он бесполезно подробный, imo. Без пространства имен вы бы просто закончили делать
anagram("thing")
, а неanagram::anagram("thing")
… Я не думаю, что это лучше. редактировать: особенно учитываяauto thing = anagram::anagram("foo");
, что это даже больше, чем простоanagram::anagram thing{"foo"};
4. @suffi ну, имеет смысл вывести ваши классы / функции из глобального пространства имен, чтобы избежать столкновения имен с кодом людей, которые этого не делают. И если ваш проект включает в себя анаграммы, было бы логично иметь пространство имен с классом
anagram
, вспомогательной функциейis_anagram
и другими вещами, которые связаны с искусством обработки анаграмм. Анаграмма имени — это первое, что приходит на ум, когда думаешь о том, как вызвать такое пространство имен. Так что, кстати, такое именование может иметь смысл. Что, безусловно, не имеет смысла, так это размещение каждого класса в уникальном пространстве имен с одинаковым именем.
Ответ №4:
Синтаксис на самом деле будет выглядеть так же, как в Java (за исключением new
, конечно) :
auto subject = Anagram("diaper");
Но есть более простой способ:
Anagram subject("diaper");
Anagram subject{"diaper"}; // C 11 and newer
Также обратите внимание, что если Anagram
есть конструктор по умолчанию, он будет создан при его определении — это не может быть null
или что-то вроде java, если вы не используете *
указатели.
Anagram subject;
Вы также можете создать временный Anagram
объект, поэтому вам не нужно определять subject
переменную :
auto matches = Anagram{"diaper"}.matches({"hello", "world", "zombies","pants"});
Если вы хотите использовать динамическое распределение, вы можете использовать new
, но нет никакого GC для удаления значения, когда вам больше не нужно …!
Anagram* subject = new Anagram("diaper");
// ... do some stuff with subject...
delete subject; // Destroy the dynamically allocated subject and deallocate it
Если вы когда-нибудь захотите использовать динамическое распределение памяти, я бы рекомендовал вам использовать интеллектуальные указатели, которые вы можете найти на этой странице cpprefrence . Они имеют много преимуществ по сравнению с ручным выделением памяти.