Using class references to modify public members within another class - c++

Since my last question had too much code in it, I tried to make the simplest example of what I'm trying to do. Take this for example,..
#include <iostream>
using namespace std;
class String
{
public:
private:
};
class ClassTwo
{
public:
int memberVariable;
private:
};
class ClassOne
{
public:
ClassOne (ClassTwo&, String&);
~ClassOne();
private:
ClassTwo& classTwoReference;
String& stringReference;
};
ClassOne::ClassOne (ClassTwo& two, String& string)
: classTwoReference (two), stringReference (string)
{
two.memberVariable = 3;
}
ClassOne::~ClassOne()
{
}
int main()
{
String stringObject;
ClassTwo classTwoObject;
ClassOne classOneObject (classTwoObject, stringObject);
}
In JUCE, which is the API I'm using to code a VST Plugin, there is a string class that JUCE names "String". I'm not sure exactly what the constructor does, but you can use something like this to create a String object.
String newString("string");
The ClassTwo in my case, is the AudioProcessor class which has a public member variable that I can access from ClassOne like this.
two.memberVariable = 3;
The ClassOne in my case, is a custom Component(I named it PixelSlider) that I'm using in my GUI. It uses a slider listener to check the status of a slider and modify the member variable in ClassTwo(AudioProcessor). I can do this fine using the method above, but the issue is that I want to create as many ClassOne(PixelSlider) objects as I need. I want to pass them a String object that tells them what member variable of ClassTwo(AudioProcessor) to modify. Logically, this would be done by passing a reference to a String object with the same string value as the name of the ClassTwo member variable. Like this,...
ClassOne::ClassOne (ClassTwo& two, String& string)
: classTwoReference (two), stringReference (string)
{
two.(string) = 3;
}
This doesn't work in JUCE, but can anybody tell me a way to get this done without having to create a bunch of different classes almost exactly like ClassOne(PixelSlider) that modify different ClassTwo(AudioProcessor) member variables?

If I understand correctly, you're trying to bind a PixelSlider target to a member of AudioProcessor at runtime, which, as you've discovered, can't be done the way you suggest ( two.(string) = 3 ). One way of achieving this binding would be to use the command pattern (http://sourcemaking.com/design_patterns/command/cpp/2).
AudioProcessor could expose a collection of these command objects for each modifiable property ...
AudioProcessorCommand
AudioProcessor::GetCommandByName(String const& properyName) const
{
...
}
... which you can pass to the constructor of PixelSlider. Something along the lines of ...
PixelSlider::PixelSlider(AudioProcessorCommand& command)
: command_{command}
{
...
}
When the PixelSlider's value changes you would invoke the command ...
command_(this->value_);

Related

Initializing a new nested class from outer class function

I'm currently learning nested classes in C++ while building a project and I currently inside setupBLE() I need to pass one of the nested classes but to init that new class I need to pass to its constructor the outer class so it can access its variables and functions but I'm not exactly sure how to pass to the constructor the pointer of the class that's trying to create it.
It's a bit confusing so I hope the code helps with it.
Like in python we have self but in C++ as far as I know we don't have that so I was wondering what should I pass to the constructor.
Code (PillDispenser.h):
class PillDispenser {
public:
explicit PillDispenser(BLEAddress deviceAddress);
private:
BLEAddress _device_address;
BLEAdvertisedDevice _device;
bool _connected;
// Device properties
std::string _device_name;
// Callbacks
static void notifyCallBack();
class AdvertisedDeviceCallBack : public BLEAdvertisedDeviceCallbacks {
PillDispenser &_outer;
explicit AdvertisedDeviceCallBack(PillDispenser &outer) : _outer(outer){};
void onResult(BLEAdvertisedDevice advertisedDevice) override;
};
}
Code (PillDispenser.cpp):
void PillDispenser::setupBLE() {
BLEScan *scanner = BLEDevice::getScan();
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack());
scanner->setInterval(SCAN_INTERVAL);
scanner->setWindow(SCAN_WINDOW);
scanner->setActiveScan(true);
scanner->start(SCAN_DURATION);
}
Issue:
This line is trying to use the default constructor which does not exist
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack());
instead you should use the explicit constructor you defined
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack(*this));
note that this (in this context) has type PillDispenser* so you have to dereference with * to get a PillDispenser&

Error trying to create map outside of main function. C++

I'm very new to C++ but I am trying to create a map and insert values into it from a class but seem to keep getting an error.
class Album {
public:
map<string,string> albums;
albums.insert(make_pair("rap","Kamikaze")); // This gives the error
};
when i put those same two lines inside the main function, it works without an issue. Like I said I'm very new to C++ so please don't roast me if it's something simple.
(Also, I have map included and using namespace std added)
You are trying to run code in a space where code isn't supposed to be. You can instead write
class Album {
public:
map<string,string> albums;
Album() {
albums.insert(make_pair("rap","Kamikaze"));
}
};
This will run the code every time the class is instantiated, effectively making it the default value for albums.
Class is not a function. Class body can only contain declarations. Executable code may only be in functions (including class methods). For example:
class Album {
public:
map<string,string> albums;
void add_album(string a, string b) {
albums.insert(make_pair(a, b));
// or: albums.emplace(a, b); // if supported
}
};
...
int main() {
...
Album my_album;
my_album.add_album("rap", "Kamikaze");
my_album.albums.insert(make_pair("some", "Thing"));
...
}
No problem its very simple. Below here is a class definition and map that you have declared is its public data member.
Now this Class will act as a prototype for all "Album" objects and all object created will have their own map member.
class Album {
public:
map<string,string> albums;
};
Consider below example,
Album objA; //Object of Album class is created here
//Map being a public member can directly be accessed here
ObjA.albums.insert(make_pair("some", "Thing"));
So instead of calling insert function in class definition you need to do it this way.
Similarly for objectB,
ObjB.albums.insert(make_pair("some", "Thing"));

i dont understand why this wont let me initialise like a normal object/instance

Basically, i am quite new to c++ and i want to know why when i create an object it wont let me initialize it in the normal way. E.g
'int example = 10;' but when i try to initialize this problem like in the code below a problem comes up about some conversion:'no suitable constructor exists to convert from "const char [7]" to "binary"'.
#include <iostream>
using namespace std;
class binary
{
public:
string value;
};
int main()
{
binary first = "101010";
return 0;
}
Neither
binary first = "101010";
nor
binary first = std::string("101010");
will work since the class does not have a constructor that takes such an argument.
You can use any one of the following:
binary first = {"101010"};
binary first = {std::string("101010")};
binary first{"101010"};
binary first{std::string("101010")};
You can do field initialization like in the other answer, but if you're using a class, I'd recommend this for more control in the class itself on how it is created:
If the value should be initialized:
using std::string; //(not using namespace std;)
class binary
{
public:
string value;
explicit binary(string initialValue) :value(std::move(initialValue)) {}
private:
binary() {} //optionally allow no initialization within class (see comments below)
};
int main()
{
binary second("101010");
return 0;
}
The empty private constructor allows the class itself to perform complex "initialization" of an instance outside the actual constructor. An example of such initialization could be reading an xml file and populating the class from the results (which could also be done by the class's client, or an Init() function within the class.) You can remove it if not needed. If it's optional to initialize from outside the class, you can move it into public:
When you do
binary first
it creates an object named "first". You need to initialize "value" inside "first" like this:
binary first;
first.value = "101010";
If I remember correctly, C++ will implicitly convert your char[7] to a string

Cannot call member function std::string class::function() without object

I know it may seem like this has been asked before but I've looked around and the static method didn't work for me. Here's my code:
struct Customer {
public:
string get_name();
private:
string customer,first, last;
};
Here's where I call the function:
void creation::new_account() {
Customer::get_name(); //line it gives the error on.
}
Here's an example of some code that compiles fine.
struct Creation { public: string get_date(); private: string date; };
then I call it the same way
void Creation::new_account() { Creation::get_date();}
Hence my confusion why one works and the other doesn't.
EDIT: Ok I get it, I just realized I was calling a function of another struct inside a function definition that's part of a different class. I got it, thanks to all who answered
It is not declared static (needs to be static std::string get_name();). However, get_name() for Customer is a specific attribute of a Customer instance so having it static does not make sense, that is the same name for all instances of Customer. Declare an object of Customer and use it. It would make sense to have the name provided to the constructor of Customer, as surely a customer cannot exist without a name:
class Customer {
public:
Customer(std::string a_first_name,
std::string a_last_name) : first_name_(std::move(a_first_name)),
last_name_(std::move(a_last_name)) {}
std::string get_name();
private:
std::string first_name_;
std::string last_name_;
};
Declare an instance of Customer:
Customer c("stack", "overflow");
std::cout << c.get_name() << "\n";
Since your get_name is not declared static, it is a member function.
You probably need some constructors in your Customer class. Assuming you have some, you could code
Customer cust1("foo123","John","Doe");
string name1 = cust1.get_name();
You need an object (here cust1) to call its get_name member function (or method).
Time to spend many hours reading a good C++ programming book.
"The static method didn't work for me". It's not a method it's how the language works.
If you want to call some method without a concrete object, you need it to be static. Otherwise, you need an object.
Your code will work with one of the following :
struct Customer {
public:
static string get_name();
private:
string customer,first, last;
};
or
void creation::new_account() {
Customer c;
//stuff
c.get_name();
}

C++ privately constructed class

How can I call a function and keep my constructor private? If I make the class static, I need to declare an object name which the compiler uses to call the constructor, which it cannot if the constructor is private (also the object would be extraneous). Here is the code I am attempting to use (it is not compilable):
I want to keep the constructor private because I will later be doing a lot of checks before adding an object, modifying previous objects when all submitted variables are not unique rather than creating new objects.
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
#include <map>
using namespace std;
using namespace tr1;
class Referral
{
public:
string url;
map<string, int> keywords;
static bool submit(string url, string keyword, int occurrences)
{
//if(Referrals.all.size == 0){
// Referral(url, keyword, occurrences);
//}
}
private:
list<string> urls;
Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(this);
}
};
struct All
{
list<Referral> all;
}Referrals;
int main()
{
Referral.submit("url", "keyword", 1);
}
What's wrong with having a private constructor and a static factory method?
class Example {
Example() { ... }
public:
static Example CreateExample() {
return Example();
}
};
Based on your main code I think what you're shooting for is a singleton, which would look something like:
class Referral
{
private:
Referral()
{
//...
}
public:
static Referral& instance()
{
static Referral instance_s;
return instance_s;
}
bool submit(string url, string keyword, int occurrences)
{
//...
}
};
Then your call in main would look like:
int main()
{
Referral::instance().submit("url", "keyword", 1);
}
Another possibility is that you're looking to keep a list of Referrals around, in which case you can use a struct and a list of them to accomplish what you're looking for:
struct Referral
{
Referral(string url, string keyword, int occurrences) :
url_m(url), keyword_m(keyword), occurrences_m(occurrences)
{ }
string url_m;
string keyword_m;
int occurrences_m;
};
typedef std::vector<Referral> ReferralSet;
Then your call in main would look like:
int main()
{
ReferralSet set;
set.push_back(Referral("url", "keyword", 1));
}
First, you need to make Submit a static function. Then you can just say
Referral::Submit( url, keyword, occurrences );
without creating a Referral instance.
Then, in your Submit function, you're only creating a temporary Referral object that disappears almost immediately. Probably what you want to do is create an instance dynamically with new. Depending on how you want to manage this, you may want to move the code pushing onto the list into Submit.
Lastly, I would make your list of Referral instances a static member variable rather than how you have it now.
(Also, passing those string arguments by reference would probably be a good idea.)
While the whole code has some smell around, you can make it work just by making slight changes that are unrelated to your question.
To make it compile, I have removed the regex include (I am not using a compiler with C++0x support) and the 'using namespace tr1'. Move the constructor implementation after the definition of the Referral global object. Change the . for a :: in the main function when you refer to a static method.
// changes...
//#include <regex>
...
//using namespace tr1;
...
class Referral {
...
Referral(string url, string keyword, int occurrences); // added ; moved the implementation bellow the Referrals variable definition
...
struct All {
...
} Referrals;
// added constructor implementation here (Referrals global must be defined before use):
Referral::Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(*this); // added dereference, this is of type Referral*, not Referral
}
int main()
{
Referral::submit("url","keyword",1);
}
Now, from a design point of view the code has a stench to it. If really want to have a global list where you add your Referral objects, consider making it a private static attribute of the Referral class so that you can have a little more control over it (only methods in the Referral class could break the contents). Make all your attributes private and provide only accessors to the functionality that user code will need (read-only access can suffice in most cases). Use initialization lists in your constructors, and initialize all members there in the same order they appear in the class definition.
With all that fixed, it still has some smell to it. The static function creates an instance of the class but the constructor is the one that includes itself in the map (??) It would make a little more sense if the constructor did not interact with the map, and the submit() method would create the object and then include it in the list...
I think you might benefit from expressing what you intend to do, many people here will help you both with design choices and reasons for them.