Here's what I want to create:
class Theme
{
public:
Theme();
bool isValid() const;
QString name() const;
private:
QString m_name;
};
class ThemeManager
{
public:
ThemeManager();
~ThemeManager();
void setCurrentTheme(const Theme& theme);
const Theme& currentTheme() const;
const Theme& theme(const QString& name) const;
private:
Theme& m_currentTheme;
QSet<Theme> m_availableThemes;
};
Here comes the tricky part:
const Theme& ThemeManager::theme(const QString& name) const
{
for (const Theme& theme : m_availableThemes)
{
if (name == theme.name())
{
return theme;
}
}
return Theme();
}
This is what I want to achieve:
ThemeManager m;
const Theme& t = theme("monokai");
if (t.isValid()) {
// Theme is valid
} else {
// Theme is not valid
}
ThemeManagers keeps a list of themes and a reference to the current one. I want to use references instead of pointers. Now if a theme it is asked for is not present in the manager's list of themes, I would like to return a reference to an invalid one which I can test using Theme::isValid. I wouldn't like to use a separate member e.g. Theme m_invalidTheme; just for this purpose.
My question is: isn't there any way to move a temporary object outside from ThemeManager::theme scope? So that t from t.isValid() is not a dangling reference which breaks the code?
Related
I have following setup:
Class DataFetcher {
public:
virtual ~DataFetcher() = default;
explicit DataFetcher(const Backends& backends);
virtual vector<Data> GetData(const vector<string>& q) const;
private:
Backends backends_;
};
Implementation:
vector<Data> DataFetcher::GetData(const vector<string>& q) {
cout << "Yikes! This was called";
...
}
Then a piece of function in another place which uses it as:
void Process(const Backends& backends) {
DataFetcher data_fetcher(backends);
...
const auto& data = data_fetcher.GetData(q);
...
}
Now I am trying to test Process with any call to GetData being mocked, as following:
class MockDataFetcher : public DataFetcher {
public:
using DataFetcher::DataFetcher;
MOCK_METHOD(vector<Data>, GetData, (const vector<string>& q), (const, override));
}
class ActualLogicTest : public ... {
protected:
Backends backends_;
}
TEST_F(ActualLogicTest, BasicOne) {
MockDataFetcher mock_data_fetcher(backends_);
vector<Data> data;
ON_CALL(mock_data_fetcher, GetData).WillByDefault(Return(data));
...
Process(backends_);
}
What is wrong in this? I am seeing that actual implementation of GetData is getting called and I am seeing that message Yikes! This was called too. Since GetData is a virtual function, it should get the empty vector of Data back as result from the mocked one. Why is that not happening?
Finally the test crashes because backend doesn't have initialization of its members.
The function doesn't use mock object at all:
void Process(const Backends& backends) {
DataFetcher data_fetcher(backends);
...
const auto& data = data_fetcher.GetData(q);
...
}
Regardless whether you create a MockDataFetcher the Process function create local DataFetcher and uses it - not the mock that you have created in test case - you need to provide it somehow to the Process function.
From your declaration:
virtual vector<Data> GetData(const vector<string>& q) const;
GetData() returns an object.
Yet, in Process(),
void Process(const Backends& backends) {
DataFetcher data_fetcher(backends);
...
const auto& data = data_fetcher.GetData(q); // BUG!! Why is data a reference?
}
The variable 'data' cannot be a reference, since the object it refers to has literally no life span. Any attempt to use 'data' will result in undefined behaviour.
I asked a question yesterday, but it seems I did ask it incorrectly, so here I go again. I quickly mocked up this code, and I'm wondering if this is a proper way to handle the objects (outside of just putting everything in main(). This would be my first time trying to complete a larger project, so I've never had a need to question how to contain and handle the objects.
skill.h
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
class Skill;
typedef std::vector<std::shared_ptr<Skill>> SkillVector;
typedef std::unordered_map<std::string, std::shared_ptr<Skill>> SkillMap;
class Skill {
private:
std::string _skill_name;
std::string _skill_description;
friend std::ostream& operator<< (std::ostream& stream, const Skill& skill);
void print(std::ostream& stream) const;
public:
Skill(const std::string& skill_name, const std::string& skill_description);
const std::string& getSkillName() const;
const std::string& getSkillDescription() const;
bool isMatch(const std::string& substring) const;
};
application.h
#pragma once
#include "skill.h"
extern std::string SKILL_FILE;
class Application {
private:
std::unique_ptr<SkillMap> _skill_map;
void loadData();
void loadSkills();
void printSkillMap();
void printSkillVector(const SkillVector& skills);
std::unique_ptr<SkillVector> skillSearch(const std::string& input) const;
public:
Application();
void run();
};
main.cpp
#include "application.h"
int main() {
std::unique_ptr<Application> application(new Application);
application->run();
return 0;
}
This is going to be a command-line application, so other than this I can't think of doing anything else except putting all the methods from the application class straight into main as regular functions. That doesn't seem like the correct approach though. I've tried researching this pretty extensively, but haven't really found anything that answers this.
What are the other options for containing all the objects in an orderly fashion? What are the advantages of doing it certain ways? And is what I'm doing here acceptable?
NOTE: This isn't an exact representation of my project, and I'm just using it as an example to understand my question at hand.
TL;DR There isn't a single answer on how to move forward. It depends on:
What your goal is.
What subsystems the project will have, and how they integrate with one another.
The type and quantity of data that the project will require.
That said, it's almost always a good idea to apply separation of concerns, segregating data & functionality between types that correspond to each of your project's concerns. Here's an example using a finite state machine to get you started:
// Note that this example uses C++11 features.
// Note that the stubs are intentional, to keep this example as terse as possible.
// For consistency with your naming style.
typedef std::string String;
template<typename T>
using Vector = std::vector<T>;
template<typename T>
using UniquePtr = std::unique_ptr<T>;
// Skill.hpp: Represents a single skill.
class Skill {
private:
String _name;
String _description;
public:
Skill(String name, String description);
const String& getName() const { return _name; }
const String& getDescription() const { return _description; }
};
// Player.hpp: Represents a single player.
class Player {
private:
Vector<Skill*> _skills;
bool _isVirtual; // Is this player from another computer? (networked multiplayer)
public:
Player(bool isVirtual = false) :
_skills(),
_isVirtual(isVirtual) {}
Player(const Player& other) = delete; // Non-copyable.
bool hasSkill(Skill* skill) const;
void addSkill(Skill* skill);
bool removeSkill(Skill* skill); // Returns true if removed, false otherwise.
bool isVirtual() const { return _isVirtual; }
};
// Level.hpp: Represents a single level of the game.
class Level {
private:
// Per-level data...
public:
Level();
Level(const Level& other) = delete; // Non-copyable.
};
// GameState.hpp: Represents the state of the game.
enum class GameState {
MainMenu, // The user is in the main menu.
World, // The user is navigating the world.
Combat, // The user is in combat.
};
// Game.hpp: Represents a single game instance.
class Game {
private:
Application* _app;
Vector<UniquePtr<Player>> _players;
Vector<UniquePtr<Level>> _levels;
Level* _level; // Current level the player(s) are on.
GameState _state; // Current state of the game.
bool _isRunning; // Is the game running?
void mainMenuLoop() {
while (_isRunning) {
// Implement your main menu here.
// Update the menu display after user input.
// When a selection is confirmed, execute it and return.
}
}
void combatLoop() {
while (_isRunning) {
// Implement your combat system here.
// When combat is over, update _state and return.
}
}
public:
Game(Application* app) :
_app(app),
_players(),
_levels(),
_level(),
_state(GameState::MainMenu),
_isRunning(true) {
// Finish initializing and:
// If loading is fast enough, do so here.
// If loading is slow, spin up a thread and load asynchronously.
}
Game(const Game& other) = delete; // Non-copyable.
void run() {
// If loading is slow, wait on the loading thread to complete.
// Possibly show an introduction banner.
while (_isRunning) {
switch (_state) {
case GameState::MainMenu:
mainMenuLoop();
break;
case GameState::Combat:
combatLoop();
break;
}
}
}
void quit() { _isRunning = false; }
const Player* getPlayer(int index) const;
Player* getPlayer(int index);
void addPlayer(Player* player);
bool removePlayer(Player* player); // Returns true if removed, false otherwise.
const Level* getLevel(int index) const;
Level* getLevel(int index);
void addLevel(Level* level);
bool removeLevel(Level* level); // Returns true if removed, false otherwise.
};
// Options.hpp: Represents command line options.
struct Options {
// Add your command line options here.
Options();
Options(const Options& other);
};
// Application.hpp: Represents a single application instance.
class Application {
private:
Options _options;
Game _game;
public:
// For compatibility with your code.
Application() :
_options(),
_game(this) {}
// For later, when you add command line options.
Application(const Options& options) :
_options(options),
_game(this) {}
Application(const Application& other) = delete; // Non-copyable.
const Options& getOptions() const { return _options; }
const Game* getGame() const { return &_game; }
Game* getGame() { return &_game; }
// For compatibility with your code. You could
// remove this and directly use getGame()->run()
void run() { _game.run(); }
};
In main using unique_ptr for the Application object is unnecessary. Use the stack instead:
// Added arguments because you'll probably want command-line options later.
int main(int argc, char** argv) {
Application app; // Better locality, no dynamic allocation.
app.run();
return 0;
}
Follow the following rules:
When you have inheritance, the classes should respond to 'is-a'. For example if you have class Speed : public Skill. That seems logical and: Speed is a Skill.
When you have composition, the classes should respond to 'has-a'. In your case: Application has a Skill map.
If the class was Hero it would be really logical: Hero has a Skill map. And this hero will develop the skills also the hero might need to print its skills... So the Hero will manage his Skills.
Sorry if I misunderstood your question.
I have the following Store class:
class Store
{
public:
Store() : m_npc_id(0)
{
}
Store(const int npc_id,
vector<std::string> categories,
vector<StoreItem> store_items) :
m_npc_id(npc_id)
{
m_categories = categories;
m_store_items = store_items;
}
Store& operator=(const Store& rhs)
{
return *this;
}
vector<std::string> GetCategories() const;
vector<StoreItem> GetItems() const;
private:
const int m_npc_id;
vector<std::string> m_categories;
vector<StoreItem> m_store_items;
};
When I call the following code, the object gets stored properly in the store variable...
const Store& store = Store(npc_id, category.second, items[npc_id]);
However, as soon as I try to insert the store variable into the a map of all Stores, it doesn't work... The object that gets stored is empty, and takes on the default constructor values for Store.
for (auto &category : categories)
{
// In this case, category.second is a string value
// items[npc_id] is a StoreItem
const int npc_id = category.first;
const Store& store = Store(npc_id, category.second, items[npc_id]);
stores[npc_id] = store;
}
Your copy assignment operator is completely wrong.
stores[npc_id] = store;
If npc_id is not found in the map, the map first creates a new Store using the default constructor. Then it attempts to copy assign from store. And it copies using this code:
{
return *this;
}
Given the fact you have a const member, it appears to be your intent to disallow copies. In which case, the code is even more wrong. To disallow copies, use Store& operator=(const Store& rhs) = delete;.
And you'll note that stores[npc_id] = store; no longer compiles. Instead, you'll have to do something to avoid the copy.
stores.emplace(std::piecewise_construct,
std::forward_as_tuple(npc_id),
std::forward_as_tuple(npc_id, category.second, items[npc_id]));
Don't like this code? Make Store copiable instead:
class Store
{
public:
Store() : m_npc_id(0) {}
Store(const int npc_id,
vector<std::string> categories,
vector<StoreItem> store_items)
:
m_npc_id(npc_id),
m_categories(std::move(categories)),
m_store_items(std::move(store_items)),
{}
const vector<std::string>& GetCategories() const;
const vector<StoreItem>& GetItems() const;
private:
int m_npc_id;
vector<std::string> m_categories;
vector<StoreItem> m_store_items;
};
stores[npc_id] = store; //now this works!
I created a singleton class
class AreaDataRepository {
private:
AreaDataRepository();
AreaDataRepository(const AreaDataRepository& orig);
virtual ~AreaDataRepository();
Way onGoingWay;
public:
static AreaDataRepository& Instance()
{
static AreaDataRepository singleton;
return singleton;
}
void SetOnGoingWay(Way onGoingWay);
Way const & GetOnGoingWay() const;
};
void AreaDataRepository::SetOnGoingWay(Way onGoingWay) {
this->onGoingWay = onGoingWay;
}
Way const & AreaDataRepository::GetOnGoingWay() const {
return onGoingWay;
}
header file of Way
class Way {
private:
std::string id;
std::string name;
public:
Way();
Way(const Way& orig);
virtual ~Way();
void SetName(std::string name);
std::string const & GetName() const;
void SetId(std::string id);
std::string const & GetId() const;
};
Then i'm created a Way object and set vales of id and name.
Way wayNode;
wayNode.SetId("123");
wayNode.SetName("jan")
AreaDataRepository::Instance().SetOnGoingWay(wayNode);
After assign OngoingWay accessing it from another class.
std::cout << AreaDataRepository::Instance().GetOnGoingWay().GetId();
the vale is not printing.
I'm going psychic here.... and I divine that your implementation of SetId is like this:
void SetId(std::string id) { id = id; }
that does not set the member variable, that sets the parameter to itself. And since your constructor most likely set the member variable id to "" you're printing empty strings. Either change the name of the parameter (to newId for example) to avoid the conflict or change the implementation to:
void SetId(std::string id) { this->id = id; }
As proof of this claim here's the result for the first version, as you see it prints nothing. And here is the result for the second, as you can see it prints the number.
The problem boils down to this: you have function parameter names that are the same as the name of your member variables and the function parameters are shadowing/hiding the member variables.
The only place this cannot happen is in a constructor's initialization list:
class Foo {
int x;
public:
Foo(int x): x(x) {} // <-- this works
void SetX(int x) { x = x; } // <-- this won't the parameter is hiding the member variable
};
Demo for the above snippet
std::cout is buffered in most implementations, if not in all. That means, the stream will wait for you to end a line before writing out any data. So, you can easily fix this by changing your output statement to
std::cout << AreaDataRepository::Instance().GetOnGoingWay().GetId() << std::endl;
I recently came across this class and was surprised at how the getters and
setters were implemented.
I have not come across this before and would welcome some second opinions.
Do you think this is a good paradigm?
Is is bad?
Is it evil?
Header:
class Tool
{
public:
Tool();
virtual ~Tool();
bool setName(const std::string &name);
bool getName(std::string &name) const;
void clearName();
private:
std::string m_name;
bool m_nameSet;
};
cpp file:
#include "Tool.h"
Tool::Tool()
: m_name("")
, m_nameSet(false)
{
}
Tool::~Tool()
{
}
bool Tool::setName(const std::string &name)
{
m_name = name;
m_nameSet = true;
return (m_nameSet);
}
bool Tool::getName(std::string &name) const
{
bool success = false;
if (m_nameSet)
{
name = m_name;
success = true;
}
return (success);
}
The way you selected for getter is not popular, programmers prefer to return data from getter
std::string getName() const;
Why an item that set before, or has an initial data, should be re-checked on getter? If you want validate the data, validate it on setter.
However if your insist to return a value as "is name set before", you can write a third method by means of bool isNameSet() const;
This looks a lot like C where it is usual to return status codes to see if a functions fails or not.
Then also there are better methods to verify that a name is set or not. One could be to use the boost::optional to me this is a better way to declare intent that the name might not be set at all times.
I would however wonder if it's not better to make sure the name is set at all times by only having one constructor that takes a std::string as a parameter.
class Tool
{
public:
//Constructor already does the right thing
Tool() = default;
virtual ~Tool();
//Use void or return the modified class, akin to operators
void setName(const std::string& name)
{
m_name = name;
}
//Alternatively
Tool& setName(const std::string &name)
{
m_name = name;
return *this;
}
//Return const reference to the value if possible, avoids copying if not needed
//This will fail at run time if name is not set
//Maybe throw an exception if that is preferred
const std::string& getName() const
{
return *m_name;
//Or
if(m_name) return *m_name;
else throw some_exception;
}
//Or return the optional, then calling code can check if name where set or not
const boost::optional<std::string>& getName() const
{
return m_name;
}
void clearName()
{
m_name = boost::optional<std::string>();
}
private:
boost::optional<std::string> m_name;
};
I wouldn't call that a paradigm. This seems to be a solution for architecture, where a field may be in unspecified state (why not? Sometimes it is a sane requirement). Though, I don't like much this solution, because getter is supposed to return value (symmetrically, setter is supposed to set it) and the convention usually requires specific prototypes:
Type GetValue();
SetValue (const Type & newValue);
or
SetValue (Type & newValue);
or
SetValue (Type newValue);
You shall choose one of three setters depending on situation, usually the first or second one fits.
If a field may be in an unspecified state, I would choose another approach, as M M. suggests in his answer, I'll take liberty to provide an example:
class C
{
private:
int field;
bool fieldSet;
public:
C()
{
field = 0;
fieldSet = false;
}
bool IsFieldSet()
{
return fieldSet;
}
int GetField()
{
if (!fieldSet)
throw std::exception("Attempt to use unset field!");
return field;
}
void SetField(const int newValue)
{
field = newValue;
fieldSet = true;
}
};
Note though, that I wouldn't call this way of implementing getters evil. It may be just uncomfortable to use.