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;
}
Related
I am writing an interface for several I/O classes.
There is a function that looks for information in different kinds of files (sometimes html, sdb, txt, ...):
bool Search(std::string file, std::string field)
However, one of these requires an additional parameter to complement the SQL query. In this case the sdb needs to specify in what table the field is located.
I am trying something like the following (it does not compile, I am aware):
class fileIO{
public:
virtual ~FileIO(){};
virtual bool Search(std::string file, std::string field,
std::string additional = 0 /* for sdb only */) = 0;
}
class readHTML : fileIO{
public:
bool Search(std::string file, std::string field); //does NOT override virtual method
Is there anything that can give me the behavior I am looking for?
Is such strategy according to C++ standards?
What else could I add to replace such enforcement on the interface?
I am sorry if the title is misleading, I am looking for an alternative with that behavior. I could not find it so far.
You don't need it, I'd say.
At the caller site, there is only two possibilities: you know your specific fileIO instance is a sdbIO or you don't. If you do, you can call an overloaded version of Search defined in sdbIO which takes this additional info. If you don't, you don't and sdbIO::Search should be defined in terms of its overloaded version.
struct fileIO
{
virtual bool Search(std::string file, std::string field) = 0;
}
struct sdbIO : fileIO
{
bool Search(std::string file, std::string field, std::string additional);
bool Search(std::string file, std::string field) override
{
Search(file, field, "");
}
};
At the caller site:
void f(fileIO& io)
{
// I know this is a sdb:
dynamic_cast<sdbIO&>(io).Search("/file", "text", "WHERE answer=42");
// I don't
io.Search("/file", "text");
}
notes: do you really need a copy of those strings?
You can hide the virtual function in the non-public interface and make the public interface (with the default argument) non-virtual.
struct Interface
{
...
// public interface calls the abstract members.
bool Search(string const&a, string const&b, string const&c = "")
{
if(c.empty() && need_third_string())
throw runtime_error("search requires an additional string argument");
return search(a,b,c);
}
protected:
virtual bool need_third_string() const = 0;
virtual bool search(string const&, string const&, string const&) const=0;
};
with obvious derivations:
struct A : Interface
{
protected:
bool need_third_string() const override
{ return false; }
bool search(string const&a, string const&b, string const&) const override
{ /* search ignoring third argument */ }
};
struct B : Interface
{
protected:
bool need_third_string() const override
{ return true; }
bool search(string const&a, string const&b, string const&c) const override
{ /* search ignoring using all 3 arguments */ }
};
I don't see any problem with above two way to handle things. Still, I have just one more.
#include<bits/stdc++.h>
#include <stdexcept>
using namespace std;
typedef struct
{
std::string arg1;
std::string arg2;
std::string arg3;
} Param;
class FileIO{
public:
virtual ~FileIO(){};
virtual void Search(Param param) = 0;
};
class ReadHTML : public FileIO{
public:
void Search(Param param)
{
if(param.arg3.length() > 0) // Some logic to handle things here.
search3(param.arg1, param.arg2, param.arg3);
else
throw std::runtime_error("Bad call with param");
}
private:
void search3(std::string arg1, std::string arg2, std::string arg3)
{
std::cout << " I am called with Html::Search3" << std::endl;
}
};
class ReadTxt : public FileIO{
public:
void Search(Param param)
{
if(param.arg1.length() && param.arg2.length()) // Some logic to handle things here.
search2(param.arg1, param.arg2);
else
throw std::runtime_error("Bad call with param");
}
private:
void search2(std::string arg1, std::string arg2)
{
std::cout << " I am called with Txt::Search2" << std::endl;
}
};
// Driver program to test above function
int main()
{
FileIO *io = new ReadHTML();
Param paramHtml = {"a", "b", "c"};
io->Search(paramHtml); // Put some try .. catch
Param paramTxt = {"a", "b"};
io = new ReadTxt(); // Put some try...catch
io->Search(paramTxt);
return 0;
}
I have recently started learning OOP in C++ and I started solving example tasks regarding it. I want to instantiate an object of the class CStudent after having created a default constructor for it. However the compiler cannot compile the code. I would like to ask why is that?
When you write inside your class:
CStudent();
CStudent(string name, string fn);
...you only declare two constructors, one default (taking no-argument) and one taking two strings.
After declaring them, you need to define them, the same way you defined the methods getName or getAverage:
// Outside of the declaration of the class
CStudent::CStudent() { }
// Use member initializer list if you can
CStudent::CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
In C++, you can also define these when declaring them inside the class:
class CStudent {
// ...
public:
CStudent() { }
CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
// ...
};
Since C++11, you can let the compiler generate the default constructor for you:
// Inside the class declaration
CStudent() = default;
This should work, As commented by Holt, You need to define constructor, You have just declared it.
#include <iostream>
#include <string>
#include <list>
using namespace std;
class CStudent {
string name = "Steve";
list<int> scores;
string fn;
public:
CStudent() {};
CStudent(string name, string fn);
string getName();
double getAverage();
void addScore(int);
};
string CStudent::getName() {
return name;
}
double CStudent::getAverage() {
int av = 0;
for (auto x = scores.begin(); x != scores.end(); x++) {
av += *x;
}
return av / scores.size();
}
void CStudent::addScore(int sc) {
scores.push_back(sc);
}
int main()
{
CStudent stud1;
cout<< stud1.getName()<< endl;
return 0;
}
I want to write a class (Class2) that uses another class (Class1).
Class1 requires 2 parameters (the 2nd parameter is always the same so no need to talk about it).
Class2 require 1 parameter, and I want to check this parameter if its valid before passing it to an object created from Class1
So my code looks like this :
class Class1
{
public:
Class1(const string & filename, some_other_parameters);
...
};
class Class2
{
Class1 C1;
public:
Class2(const string & filename) // I want to verify this filename before passing it to C1 object
};
Class2::Class2(const string & filename)
: C1(filename, some_other_parameters){
}
int main()
{
Class2 myClass("file.txt");
}
So is there a way to check the filename before passing it to C1 or should I do it in the main() ?
Just invoke a static function to do the validation, but otherwise forward it's argument:
class Class2
{
Class1 C1;
static const std::string& validate_filename(const std::string& filename);
public:
Class2(const string & filename)
};
const std::string& Class2::validate_filename(const std::string& filename)
{
if (filename.size() < 2)
throw std::runtime_error("filename too short");
return filename;
}
Class2::Class2(const string & filename)
: C1(validate_filename(filename), some_other_parameters){
}
Note that you can use a similar technique if you want to transform the argument. So you can convert from wide char to utf8 and force the path to be in a canonical format, ... and still have the member variable be const.
You should also consider which class should be responsible for the validation. If C1 has constraints on its arguments, then it should check them. If on the other hand it would be fine with any string, but C2 has constraints, then it must do the checking.
You can just used a pointer for Class1
#include "stdafx.h"
#include <string>
class Class1
{
public:
Class1(const std::string & filename, int a)
{
// ...
}
};
class Class2
{
Class1 * p_C1;
public:
Class2(const std::string & filename)
{
// ------------------------------------
// Check the file before p_C1 creation
// ------------------------------------
p_C1 = new Class1(filename, 1);
}
~Class2(void)
{
if (p_C1 != NULL) delete p_C1;
}
};
int main()
{
Class2 myClass("file.txt");
}
I have this class:
class CComputer {
public:
// constructor
CComputer(string name) {
this->name = name;
};
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component const & component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
string name;
string address;
list<Component> listOfComponents;
};
and then these classes:
// ancestor for other classes...It's really dummy yet, but I dunno what to add there
class Component {
public:
Component() {};
~Component() {};
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) {
this->mem = mem;
};
int mem;
};
Now I feed my CComputer class with some values:
CComputer c("test.com");
c . AddAddress("123.45.678.910") .
AddComponent(CCPU(8, 2400)) .
AddComponent(CCPU(8, 1200)).
AddComponent(CMemory(2000)).
AddComponent(CMemory(2000)));
And now I would like to print it out with all the info I've put in there (CCPU & CMemory details including)
but how to implement it, to be able to iterate through CComputer::listOfComponents and don't care if I acctually access CCPU or CMemory ? I can add it to that list, but I have really no idea, how to make it, to be able to access the variables of those components.
So the output should look like:
##### STARTING #####
CComputer:
name:test.com
address:123.45.678.910
CCPU:
cores:8,freq:2400
CCPU:
cores:8, freq:1200
CMemory:
mem:2000
CMemory:
mem:2000
###### FINISHED! #####
As others have mentioned, you need to implement a virtual function (e.g. virtual std::string ToString() const = 0;) in the base class that is inherited and overridden by each child class.
However, that isn’t enough. Your code exhibits slicing which happens when you copy your child class instances into the list: the list contains objects of type Component, not of the relevant child class.
What you need to do is store polymorphic instances. Values themselves are never polymorphic, you need to use (smart) pointers or references for this. References are out, however, since you cannot store them in a standard container (such as std::list). Using raw pointers is considered bad style nowadays, but judging from the naming conventions of your classes you don’t learn modern C++ in your class (sorry!).
Therefore, raw pointers is probably the way to go. Change your code accordingly:
Store a list of pointers:
list<Component*> listOfComponents;
Make the argument type of AddComponent a pointer instead of const&.
Call the function by passing a newed object, e.g.:
AddComponent(new CCPU(8, 2400))
Now your code leaks memory left, right and center. You need to implement a destructor to free the memory:
~CComputer() {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i)
delete *i;
}
But now your code violates the Rule of Three (read this article! It’s important, and it may be the most useful thing about C++ you’re going to learn in this programming class) and consequently you also need to implement the copy constructor and copy assignment operator. However, we can’t. Sorry. In order to implement copying for your class, you would have to implement another virtual function in your Component class, namely one that clones an object (virtual Component* Clone() const = 0;). Only then can we proceed.
Here’s a sample implementation in CCPU:
Component* Clone() const {
return new CCPU(cores, freq);
}
… this needs to be done in all classes deriving from Component, otherwise we cannot correctly copy an object of a type that derives from Component and is hidden behind a pointer.
And now we can implement copying in the CComputer class:
CComputer(CComputer const& other)
: name(name)
, address(addess) {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
}
CComputer& operator =(CComputer const& other) {
if (this == &other)
return *this;
name = other.name;
address = other.address;
listOfComponents.clear();
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
return *this;
}
This code is brittle, not thread-safe and error-prone and no competent C++ programmer would ever write this1. Real code would for instance use smart pointers instead – but as mentioned before I’m pretty sure that this would be beyond the scope of the class.
1 What does this make me now, I wonder?
Just add a virtual method to Class Component called e.g. toString(), which returns a string describing the component. Then you can iterate through all components and call toString() without worrying about exactly what each component is. If you do that, then for each computer you would be able to print out the values of all the components.
However, as pointed out in one of the comments, the example output you give in the question outputs the CCPU for all computers, then all the memory for all computers. To order the output like that, you'll need to add another virtual method to Component called e.g. getType() which returns an enum or integer that represents the type of the information. You can then have two for-next loops, one nested inside the other, where the outer loop iterates through all the types and the inner loop iterating through all the computers calling the toString() on all components which match the type specified in the outer for loop.
Here's something that implements this idea.
#include <iostream>
#include <string>
#include <list>
using namespace std;
int const TYPE_CCPU = 1;
int const TYPE_MEMORY = 2;
class Component {
public:
virtual int GetType() { return -1; }
virtual std::string ToString() const {
return "OOPS! Default `ToString` called";
}
};
class CComputer {
public:
typedef std::list<Component*>::iterator iter_t;
// constructor
CComputer(string name) {
this->name = name;
};
~CComputer() {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
delete *i;
}
}
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component *component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
void PrintType(int type) {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
if ((*i)->GetType() == type)
std::cout << (*i)->ToString() << '\n';
}
}
string name;
string address;
list<Component*> listOfComponents;
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int GetType() { return TYPE_CCPU; }
std::string ToString() const {
return "CCPU::ToString()";
}
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) { this->mem = mem; };
int GetType() { return TYPE_MEMORY; }
std::string ToString() const {
return "CMemory::ToString()";
}
int mem;
};
typedef std::list<CComputer*>::iterator iter_c;
int main() {
list<CComputer*> computerlist;
CComputer *c1 = new CComputer("test.com"), *c2 = new CComputer("test2.com");
c1->AddAddress("123.45.678.910").
AddComponent(new CCPU(8, 1200)).
AddComponent(new CMemory(2000));
computerlist.push_back(c1);
c2->AddAddress("987.65.432.10").
AddComponent(new CCPU(8, 2400)).
AddComponent(new CMemory(4000));
computerlist.push_back(c2);
for(int t=TYPE_CCPU; t<=TYPE_MEMORY; t++)
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
(*i)->PrintType(t);
}
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
delete (*i);
}
}
Implement ToString() in each of your classes. In .NET this is a standard even the "object" type implements.
I have a class called Object which stores some data.
I would like to return it by reference using a function like this:
Object& return_Object();
Then, in my code, I would call it like this:
Object myObject = return_Object();
I have written code like this and it compiles. However, when I run the code, I consistently get a seg fault. What is the proper way to return a class object by reference?
You're probably returning an object that's on the stack. That is, return_Object() probably looks like this:
Object& return_Object()
{
Object object_to_return;
// ... do stuff ...
return object_to_return;
}
If this is what you're doing, you're out of luck - object_to_return has gone out of scope and been destructed at the end of return_Object, so myObject refers to a non-existent object. You either need to return by value, or return an Object declared in a wider scope or newed onto the heap.
You can only use
Object& return_Object();
if the object returned has a greater scope than the function. For example, you can use it if you have a class where it is encapsulated. If you create an object in your function, use pointers. If you want to modify an existing object, pass it as an argument.
class MyClass{
private:
Object myObj;
public:
Object& return_Object() {
return myObj;
}
Object* return_created_Object() {
return new Object();
}
bool modify_Object( Object& obj) {
// obj = myObj; return true; both possible
return obj.modifySomething() == true;
}
};
You can only return non-local objects by reference. The destructor may have invalidated some internal pointer, or whatever.
Don't be afraid of returning values -- it's fast!
I will show you some examples:
First example, do not return local scope object, for example:
const string &dontDoThis(const string &s)
{
string local = s;
return local;
}
You can't return local by reference, because local is destroyed at the end of the body of dontDoThis.
Second example, you can return by reference:
const string &shorterString(const string &s1, const string &s2)
{
return (s1.size() < s2.size()) ? s1 : s2;
}
Here, you can return by reference both s1 and s2 because they were defined before shorterString was called.
Third example:
char &get_val(string &str, string::size_type ix)
{
return str[ix];
}
usage code as below:
string s("123456");
cout << s << endl;
char &ch = get_val(s, 0);
ch = 'A';
cout << s << endl; // A23456
get_val can return elements of s by reference because s still exists after the call.
Fourth example
class Student
{
public:
string m_name;
int age;
string &getName();
};
string &Student::getName()
{
// you can return by reference
return m_name;
}
string& Test(Student &student)
{
// we can return `m_name` by reference here because `student` still exists after the call
return stu.m_name;
}
usage example:
Student student;
student.m_name = 'jack';
string name = student.getName();
// or
string name2 = Test(student);
Fifth example:
class String
{
private:
char *str_;
public:
String &operator=(const String &str);
};
String &String::operator=(const String &str)
{
if (this == &str)
{
return *this;
}
delete [] str_;
int length = strlen(str.str_);
str_ = new char[length + 1];
strcpy(str_, str.str_);
return *this;
}
You could then use the operator= above like this:
String a;
String b;
String c = b = a;
Well, it is maybe not a really beautiful solution in the code, but it is really beautiful in the interface of your function. And it is also very efficient. It is ideal if the second is more important for you (for example, you are developing a library).
The trick is this:
A line A a = b.make(); is internally converted to a constructor of A, i.e. as if you had written A a(b.make());.
Now b.make() should result a new class, with a callback function.
This whole thing can be fine handled only by classes, without any template.
Here is my minimal example. Check only the main(), as you can see it is simple. The internals aren't.
From the viewpoint of the speed: the size of a Factory::Mediator class is only 2 pointers, which is more that 1 but not more. And this is the only object in the whole thing which is transferred by value.
#include <stdio.h>
class Factory {
public:
class Mediator;
class Result {
public:
Result() {
printf ("Factory::Result::Result()\n");
};
Result(Mediator fm) {
printf ("Factory::Result::Result(Mediator)\n");
fm.call(this);
};
};
typedef void (*MakeMethod)(Factory* factory, Result* result);
class Mediator {
private:
Factory* factory;
MakeMethod makeMethod;
public:
Mediator(Factory* factory, MakeMethod makeMethod) {
printf ("Factory::Mediator::Mediator(Factory*, MakeMethod)\n");
this->factory = factory;
this->makeMethod = makeMethod;
};
void call(Result* result) {
printf ("Factory::Mediator::call(Result*)\n");
(*makeMethod)(factory, result);
};
};
};
class A;
class B : private Factory {
private:
int v;
public:
B(int v) {
printf ("B::B()\n");
this->v = v;
};
int getV() const {
printf ("B::getV()\n");
return v;
};
static void makeCb(Factory* f, Factory::Result* a);
Factory::Mediator make() {
printf ("Factory::Mediator B::make()\n");
return Factory::Mediator(static_cast<Factory*>(this), &B::makeCb);
};
};
class A : private Factory::Result {
friend class B;
private:
int v;
public:
A() {
printf ("A::A()\n");
v = 0;
};
A(Factory::Mediator fm) : Factory::Result(fm) {
printf ("A::A(Factory::Mediator)\n");
};
int getV() const {
printf ("A::getV()\n");
return v;
};
void setV(int v) {
printf ("A::setV(%i)\n", v);
this->v = v;
};
};
void B::makeCb(Factory* f, Factory::Result* r) {
printf ("B::makeCb(Factory*, Factory::Result*)\n");
B* b = static_cast<B*>(f);
A* a = static_cast<A*>(r);
a->setV(b->getV()+1);
};
int main(int argc, char **argv) {
B b(42);
A a = b.make();
printf ("a.v = %i\n", a.getV());
return 0;
}
It isn't really good practice to return an initiated object as it does go out of scope. There are rare instances that this is the desired option. It actually can be done if the class is a referencing counting smart pointer or some other smart pointer.
How does a reference-counting smart pointer's reference counting work?