Create a new structure inside a class public method - c++

Hello I am trying to create a new structure inside my class but i think there is an issue with public and private scope of some sort.
typedef struct Currency
{
Currency(Coin *coin, Currency *next, int _position) : _coin(coin), _next(next), _position(0) {}
Currency() : _next(NULL), _position(0) {}
Coin *_coin;
Currency *_next;
int _position;
};
that is my structure that is inside my public section of my class
and when I try to do this
if(location <= exit)
{
start = location + 11;
begin = response.find("label", start);
end = begin - start - 3;
findStrings(start, end, s, &response);
curr._next = new Currency();
}
it says Expected type specifier for the new Currency() call.
is there something i am missing or should structures not be used this way?
class Exchange
{
public:
typedef struct Badge
{
Badge(std::string id, Badge next, Badge prev, int length) : _id(id), _next(&next), _prev(&prev), _position(length) {}
Badge() : _id(""), _next(NULL), _prev(NULL), _position(0) {}
std::string _id;
Badge *_next;
Badge *_prev;
int _position;
};
typedef struct Currency
{
Currency(Coin *coin, Currency *next, int _position) : _coin(coin), _next(next), _position(0) {}
Currency() : _next(NULL), _position(0) {}
Coin *_coin;
Currency *_next;
int _position;
};
/* constructor and destructor */
Exchange();
Exchange(std::string str);
~Exchange();
/* Assignment operator */
Exchange& operator =(const Exchange& copyExchange);
void parseTradePairs(Currency curr, const std::string response, int begin, int exit);
private:
std::string _exch;
Currency *_currencies;
Badge *_ident;
};
endif
^ that is in the class header
Exchange::Exchange()
{
_exch = "";
}
Exchange::Exchange(std::string str)
{
_exch = str;
_ident = new Badge;
_currencies = new Currency;
std::string pair;
std::string response;
CURL *curl;
getTradePairs(curl, response);
int exit = response.find_last_of("marketid");
parseTradePairs(*_currencies, response, 0, exit);
}
void parseTradePairs(Exchange::Currency curr, std::string response, int begin, int exit)
{
int start;
int end;
string s;
int location = response.find("marketid", begin);
if(location <= exit)
{
start = location + 11;
begin = response.find("label", start);
end = begin - start - 3;
findStrings(start, end, s, &response);
curr._next = new Currency();
}
}
^that is in the class cpp obviously.

Your function definition in the .cpp isn't related to the Exchange class. You'll need to write:
void Exchange::parseTradePairs
(Exchange::Currency curr, std::string response, int begin, int exit)
{
// ...
}
Also: Anywhere outside your class scope you'll need to use Exchange::Currency to access the type.

If you're instantiating Currency within a method of the class, then this should work fine.
But if you're instantiating Currency elsewhere, you'll need to scope it with the class' name.
I.e. ClassName::Currency
Of course Currency needs to be visible in the scope that you do that, and making it public should take care of that.

(Note: This not an answer to edited question, downvote to request deletion... :-)
One issue is this:
typedef struct Currency {
};
It compiles, but C++ compiler should say something like warning: 'typedef' was ignored in this declaration (and if it does not, enable warning!). You should use one of these:
struct Currency {
}; // type 'struct Currency' With implicit typedef in C++
which in C++ is essentially same as:
typedef struct Currency {
} Currency; // explicit typedef
or
typedef struct {
} Currency; // anonumous struct With typedef type name
It is generally best to use the first form in C++. There may be subtle differences in some corner cases, so keep things simple.
C does not do the implicit typedef, so 2nd or 3rd form are sometimes used to avoid needing to use struct keyword everywhere. This is good to know because many libraries have same .h files for both C and C++.

Related

Is there a way to refer to a later defined struct (either by prototyping or else)?

I am trying to use struct for defining in a centralized way how xml nodes are defined that I want to read by my code.
This currently looks like this:
const struct sXmlRootDefinition
{
const char* name = "case";
const char* parents[1] = { "none" };
} sRootDefinition;
//--------------------
// LEVEL 1 nodes
//--------------------
const struct sXmlCaseDefDefinition
{
const char* name = "case_definition";
const char* parents[1] = { sRootDefinition.name };
} sCaseDefDefinition;
In the second struct I have the member parents that indicate that this node is child to the node managed by sXmlRootDefinition struct.
I really would like to also implement a child member. For sXmlRootDefinition this should for instance look like:
const char* childs[1] = { sCaseDefDefinition.name };
As sCaseDefDefinitio is defined later this obviously will fail and it does fail. Of course I could reverse the order but then I run into trouble with the parent member.
Trying to prototype the later defined struct: Either it doesn't work or I am using wrong syntax.
Is there a way do achieve what I would like to achieve and if so how can I approach this?
EDIT:
This is what I tried:
struct sXmlCaseDefDefinition
{
const char* name;
const char* parents[1];
} sCaseDefDefinition;
const struct sXmlRootDefinition
{
const char* name = "case";
const char* parents[1] = { "none" };
const char* childs[1] = { sCaseDefDefinition.name };
} sRootDefinition;
//--------------------
// LEVEL 1 nodes
//--------------------
sCaseDefDefinition.name = "case_definition";
sCaseDefDefinition.parents[0] = sRootDefinition.name;
It is not working.
You can use a proper constructor, and maybe use the standard library for strings and dynamic arrays:
#include <vector>
#include <string>
struct XmlRootDefinition
{
std::string name = "case";
std::string parent = "none";
std::vector<std::string> children;
};
struct XmlCaseDefDefinition
{
XmlCaseDefDefinition(XmlRootDefinition& parent) :
parent(parent.name)
{
parent.children.push_back(this->name);
}
std::string name = "case_definition";
std::string parent;
};
XmlRootDefinition rootDefinition;
const XmlCaseDefDefinition caseDefDefinition(rootDefinition);
You can do a forward declaration:
i.E.:
struct MyStruct;
After this you can use it, as long as you don't dereference it, or declare a member, which requires the size to be known.
So this would be ok because the size of the struct doesn't need to be known:
void MyFunc(struct MyStruct *ptr);
void MyFunc()
{
struct MyStruct *ms;
}
However, if you write a function that needs to know the size, it will require the full definition:
void MyFunc()
{
// size is unknown here.
struct MyStruct ms;
}

c++ when working with class containing vectors - candidate expects 2 arguments, 0 provided

class myItem {
int key;
string name;
public:
// Constructor
myItem(int key, string name)
{
key = key;
name = name;
}
};
class myCollection {
vector<myItem> col;
public:
void insert(myItem &i);
void print();
};
int main() {
myCollection c;
int key;
string name;
cin >> key;
cin >> name;
myItem i = myItem(key, name);
c.insert(i);
c.print();
}
When I try to compile this, I get the error: no matching function for call to ‘myItem::myItem()’ and note: candidate: myItem::myItem(int, std::string). candidate expects 2 arguments, 0 provided. How might I fix this? Thanks!
First off, I am not a fan of confusing the compiler with similar names. This is terrible practice (and I am not a fan of the java this.local = param)
And even if you can argue the compiler knows what is right, someone maintaining your code will not. So you could at least capitalize or suffic and underscore or something else if you don't want to rename (sometimes I saw prefixing it with in, like inKey, inName as an alternative method which I am all in favor for, the underscore is a good if you don't want to make the name change to stand out, just make sure the underscore is not in front of the variable/parameter name):
int key;
string name;
public:
// Constructor
myItem(int key_, string name_) : key(key_), name(name_) {}
Moving on, I don't get your error but I do get unresolved externals. The problem is myCollection is defined, but not implemented (or rather its methods aren't). Try an empty placeholder using {}.
class myCollection {
vector<myItem> col;
public:
void insert(myItem &i) {}
void print() {}
};
This should fix your errors.
Your Constructor is named Team and not myItem
Replace it with
myItem(int key, string name)
{
key = key;
name = name;
}
The vector you are using in myCollection internally uses the default constructor. Try using a pointer of myItem in the vector or specify the default and copy constructors too.

Get classes with at least two same access specifiers with ASTMatcher

I need to catch cases in C++ code when there are two or more similar access specifiers in the class.
Let's say there are two classes
class A{
public:
int b;
public:
int a;
}
class B{
public:
int a;
}
How to match class A (because it has two 'public's) but not class B with ASTMatcher?
This matcher grabs the 'public' declaration:
accessSpecDecl(
isPublic(),
hasAncestor(cxxRecordDecl().bind("crd"))).bind("asd")
In the callback class, you can track the number of hits the matcher gets for a given struct declaration, for example with a std::map<string,int>:
struct report_public : public MatchCallback{
using map_t = std::map<string,int>;
using map_it = map_t::iterator;
map_t count;
void run(MatchResult const & result){
AccessSpecDecl const * asd = result.Nodes.getNodeAs<AccessSpecDecl>("asd");
CXXRecordDecl const * crd = result.Nodes.getNodeAs<CXXRecordDecl>("crd");
if(asd && crd){
string const struct_name = crd->getNameAsString();
map_it it = count.find(struct_name);
if(it != count.end()) count[struct_name]++;
else count[struct_name] = 1;
}
else { /* error handling */}
return;
} // run
}; // report_public

Having trouble with string array searching for another string in my function

I keep getting an error saying I needed a class type when I have one stated. I'm not really sure what I'm doing wrong.
I'm having trouble with the bool SellerHasName.
enum ComputerType { DESKTOP, LAPTOP, TABLET, HANDHELD };
const int MAX_NAME_LEN = 51;
class Seller
{
private:
float salestotal;
int computersSold[NUM_COMPUTER_TYPES];
char name[MAX_NAME_LEN];
public:
// default constructor
Seller()
{
name[MAX_NAME_LEN];
salestotal = 0.0;
computersSold[DESKTOP];
computersSold[LAPTOP];
computersSold[TABLET];
computersSold[HANDHELD];
}
Seller ( char name[] )
{
name[MAX_NAME_LEN];
salestotal = 0.0;
computersSold[DESKTOP];
computersSold[LAPTOP];
computersSold[TABLET];
computersSold[HANDHELD];
}
// Returns true if the seller's name is the same as nameToSearch;
// false otherwise.
// Params: in
bool SellerHasName ( char hasname[] ) const
{
return (Seller::name[MAX_NAME_LEN].compare(hasname[MAX_NAME_LEN]) == 0);
}
The error is caused by the Seller:: prefix in Seller::name[MAX_NAME_LEN]. There's no need to prefix class member variables with the class name; just write: name[MAX_NAME_LEN].
Since you are using C++ and not C, forget about C-style arrays. Particularly, char arrays in C++ are almost always a bad idea. With std::string and std::array (or std::vector for that matter) things get much much simpler and therefore maintainable:
class Seller {
private:
float salestotal;
std::array<int, NUM_COMPUTER_TYPES> computersSold;
std::string name;
public:
Seller()
: salestotal(0.0)
{}
Seller (const std::string& nm)
: name(nm)
, salestotal(0.0)
{}
bool SellerHasName(const std::string& nm) const {
return (name == nm);
}
};

a function instead of copy-and-paste programming

I have an object, every member variable in this object has a name which I can acquire it by calling get_name() ,what I want to do is concatenate all the names of the member variables in alphabetical order, then do something. for example:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
}
//skip the get_name(), set_name() and others
private:
string m_local_name;
T m_type_var;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
...
}
I have to hard-code like this:
object o;
string sign = o.m_base.get_name();
sign += o.m_team.get_name();
I need a function to do this instead of copying and pasting when the object varies. Anyone has an idea?
One way to do this in normal C++, provided all of the members belong to the same class or are derived from some base class will be to use variable number of arguments to a function. An example follows.
#include <stdarg.h>
string concatenateNames(int numMembers, ...)
{
string output;
va_list args;
va_start(args, numMembers);
for(int i = 0; i < numMembers; i++)
{
MemberClass *pMember = va_arg(args, MemberClass*);
output += pMember->get_name();
}
va_end(args);
return output;
}
class Object
{
public:
MemberClass x;
MemberClass y;
MemberClass z;
};
int main()
{
Object o;
string sign = concatenateNames(3, &o.x, &o.y, &o.z);
}
If the types of all the members are different, you can look into variadic templates of C++11x: http://en.wikipedia.org/wiki/Variadic_Templates, but I can't seem to find a way to do otherwise.
If variables which have name have a same type (or these types belongs one hierarchy) you can use map of these vars. Is not good way, but maybe it helps you
Example
class object
{
public:
object() //: m_team("team"), m_base("base")
{
this->vars["m_team"] = CXMLWrapper<string>("team");
//.....
}
public:
map<string, CXMLWrapper<string> > vars;
/*CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;*/
...
}
object o;
string sign;
for(auto& x : o.vars)//i cannot remember syntax of for of map
sign += x.get_name;
PS Sorry for my writing mistakes. English in not my native language.
One method is to have an external library of member names which the CXMLWrapper class updates:-
class BaseXMLWrapper
{
public:
void ListMembers (const char *parent)
{
// find "parent" in m_types
// if found, output members of vector
// else output "type not found"
}
protected:
void RegisterInstance (const char *parent, const char *member)
{
// find 'parent' in m_types
// if not found, create a new vector and add it to m_types
// find 'member' in parent vector
// if not found, add it
}
private:
static std::map <const std::string, std::vector <const std::string> >
m_types;
};
class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
RegisterInstance (parent, p_name);
}
// you could override assignments, copy and move constructors to not call RegisterInstance
//skip the get_name() set_name()
private:
m_local_name;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string, "object"> m_team;
CXMLWrapper<string, "object"> m_base;
...
};
This does add overhead to the construction of objects, but as it's only a constructor overhead it might not affect overall system performance much.
This looks like a "observe pattern", you just need to keep a single copy in object as a member variable "string name_;", and pass the name_s's reference into CXMLWrapper like this:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const string &name)
: local_name_(name)
{
}
//skip the get_name() set_name()
private:
const string &local_name_;
}
class object
{
public:
object()
: team_("team"),
base_("base"),
m_team(team_)
, m_base(base_)
{
}
public:
string team_;
string base_;
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
}