Привет! Я питонист, но из приличия решил заботать с++.
Задание: есть класс Foo
с private
конструктором. Есть функция foo_says
которая использует public
метод класса Foo
. Надо написать функцию get_foo
, благодаря которой будет компилиться:
foo_says(get_foo("Hello!"));
Код:
#include <iostream>
#include <stdio.h>
#include <cstddef> // size_t
#include <cstring> // strlen, strcpy
using namespace std;
struct Foo {
void say() const { std::cout << "Foo says: " << msg << "\n"; }
protected:
Foo(const char *msg) : msg(msg) { }
private:
const char *msg;
};
struct Fo : Foo {
Fo(const char* msg) : Foo(msg) { }
};
void foo_says(const Foo &foo) {
foo.say(); }
const Foo& get_foo(const char *msg) {
const Fo F(msg);
const Foo& f = F;
return f;;
}
int main()
{
foo_says(get_foo("Hello!"));
return 0;
}
Решение и проблема: Так как задание из раздела "Наследование классов", то я наследовал Fo
, который создаст объект, а потом его можно будет привести(срезкой) к объекту Foo
. Но вместо строки Hello я получаю ��.��. Подозреваю, что после выхода из какой то функции удаляется указатель на Hello, потому что "Foo says" выводится исправно. Тогда где это происходит - понять не могу?
Начнем с того, что у вас же задано
класс Foo
с private
конструктором
а вы делаете protected
. Чтобы достучаться до private
конструктора, нужен только друг. Так что если позарез нужно наследование, то объявите наследник другом:
class Fo;
class Foo
{
Foo(const char *msg) : msg(msg) { }
public:
void say() const { std::cout << "Foo says: " << msg << "\n"; }
private:
string msg;
friend class Fo;
};
class Fo : public Foo {
public:
Fo(const char* msg) : Foo(msg) { }
};
Что касается функции get_foo
, то в ней можно выкрутиться (@Majestio рассказал вам, в чем в ней неприятности), либо возвращая указатель
const Foo* get_foo(const char *msg)
{
return new Fo(msg);
}
либо ссылку на статический объект:
const Foo& get_foo(const char *msg)
{
static Fo(msg);
return Fo;
}
Минус второго решения очевиден - объект один, и вы не сможете создать второй. Минус первого - в возврате указателя, который надо хранить и не забыть потом удалить.
Главный проектный минус - что вы хотите возвращать ссылку на Foo
, которая фактически является ссылкой на Fo
.
Лично я бы решал задачу без наследования, ибо в условии о нем ни слова, а для доступа к private
конструктору все равно нужна дружба:
class Foo
{
Foo(const char *msg) : msg(msg) { }
public:
void say() const { std::cout << "Foo says: " << msg << "\n"; }
private:
string msg;
friend Foo get_foo(const char *msg);
};
void foo_says(const Foo &foo)
{
foo.say();
}
Foo get_foo(const char *msg)
{
return Foo(msg);
}
int main()
{
foo_says(get_foo("Hello!"));
}
Кстати, обратите внимание на то, что член msg
я сделал string
- сейчас это не принципиально, но вдруг вы еще как-то захотите использовать этот класс, и будете передавать в конструктор не литерал...
const Foo& get_foo(const char *msg) {
const Fo F(msg);
const Foo& f = F;
return f;;
}
Вот тут вы возвращаете ссылку на объект локальной видимости. Это ведет к состоянию "неопределенного поведения" (undefined behavior). Пока это не решено - дальше "копать" смысла нет.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Написал простенький класс для отправки post запросаПроблема в том что на строчке
Здравствуйте, скачал сегодня кандидат-версию Visual Studio 17 ProНу решил посмотреть что да как
На данный момент длина кода - 127 символов без пробелов, табуляция и знаков новой строкиЗадача уменьшить длину кода хотя бы до 125 символов, что...