I am trying to write this program using base classes and derived classes where there is a truck with a maximum capacity of 8 tons. Then this truck is loaded with 1.5 tons of apple and then loaded with 0.5 tons of kiwi. This would then diminish the amount of tons remaining to 6.5 when the apples are loaded and then to 6 when the kiwis are loaded. This is an assignment and in the main function I see they are calling the function loadCargo as follows truck.loadCargo(Apple()), I am unsure of what this is accomplishing. Please take a look at the complete code:
#include <iostream>
#include <string>
using namespace std;
class Cargo{
public:
double c = 0;
double getAmount(){
return c;
}
};
class Apple : public Cargo{
public:
double c = 1.5;
double getAmount(){
return c;
}
};
class Kiwi : public Cargo{
public:
double c = 0.5;
double getAmount(){
return c;
}
};
class Truck {
double maxCapacity = 8;
public:
void loadCargo(Cargo cargo){
maxCapacity = maxCapacity - cargo.getAmount();
}
void printInfo(){
cout << maxCapacity << " tons remaining" << endl;
}
};
int main() {
Truck truck;
truck.printInfo();
truck.loadCargo(Apple());
truck.printInfo();
truck.loadCargo(Kiwi());
truck.printInfo();
}
I thought that truck.loadCargo(Apple()) would pass an object of Apple to the object cargo. Therefore when loadCargo is called, it would access the getAmount function in Apple class and not in class Cargo but that is not happening. The output should be:
8 tons remaining
6.5 tons remaining
6 tons remaining
But currently it is the following since it just using the getAmount from the Cargo class:
8 tons remaining
8 tons remaining
8 tons remaining
EDIT: Since this is an assignment I cannot change anything in the main function or in the line that has void loadCargo(Cargo cargo).
First, you need to make your getAmount() function virtual:
class Cargo{
public:
double c = 0;
virtual double getAmount(){
return c;
}
};
Then, your derived classes will override the getAmount() function with their version.
Without the virtual keyword, if your function accepts a parameter of type Cargo, it will just used the Cargo::getAmount() function.
Second, you need to pass your object into by const-reference, like this:
class Truck {
double maxCapacity = 8;
public:
void loadCargo(const Cargo& cargo){
maxCapacity = maxCapacity - cargo.getAmount();
}
...
This will ensure that your cargo object inside the loadCargo function will refer to an Apple object or a Kiwi object. By passing by value, you're copying your Apples object into a Cargo object, and you fall over the slicing problem.
ETA: You would also need to change your getAmount() function to const like this:
// vvvvv
double getAmount() const {
return c;
}
Since you mention you cannot change your Truck class, you can do this by setting the value of c in your Cargo class constructor. Like this:
class Cargo{
public:
double c;
// Constructor, using an initializer list to set the value of `c`.
Cargo(const double c_value) :
c(c_value) {
}
double getAmount(){
return c;
}
};
Then, in your Apple and Kiwi classes, set the value of c inside the constructor, like this:
class Apple : public Cargo{
public:
// Set the Cargo's mass in the Apple constructor...
Apple() :
Cargo(1.5) {
}
// getAmount() function removed.
};
Finally, remove the getAmount() functions from your Apple and Kiwi classes (but KEEP for the Cargo class).
Final Note
Please bear in mind that passing Cargo by value will always suffer from the Slicing Problem (see link above) and should be avoided, though because your Apple and Kiwi objects don't have any member variables, it will still work for your assignment. If inheritance is how your instructor wanted this to work, then passing Cargo by value into loadCargo(Cargo cargo) is bad C++ practice. This doesn't impact your assignment, but if you wish to take C++ seriously, bear this in mind for the future!
When you make this call:
truck.loadCargo(Apple());
You are indeed passing an Apple to truck. However, the declaration of loadCargo takes a Cargo object:
void loadCargo(Cargo cargo)
This slices the Apple and now you simply have a Cargo object that you call getAmount on. This returns 0, and so the maxCapacity doesn't change.
There are various ways to fix this, but the simplest would be to make loadCargo a template, so that it can accept any type without first converting it to a Cargo object:
template<typename Fruit>
void loadCargo(Fruit cargo)
Here's a demo.
Note that for this implementation, so long as Apple and Kiwi have the same member functions as expected of a Cargo object, you can avoid inheriting from a base class entirely.
Related
I am a newbie in C++. Here in my case I have created two classes, class One and class Two. _x is declared as a private member variable of class One. So here I am trying to learn different methods to access this private variable(_x) from any other class(Here in this case it is class Two). This is my scenario basically. So one method I tried is ,making class Two as a friend class of class One and for accessing this variable, I have used directValOfOne function to print the value of this variable and another one I tried was passing the address of the class One instance in another member function (getDataTwo) of class Two. Everything works well until here.
As you can see, I have initialized the _x using a parameterized constructor and printing this variable gives me the value as 10 using both the methods. Again I modified this variable using a
setter function (setDataOne) to 220 and when I print it using the getDataTwo function it prints the value as 220. But when I tried to print the value using directValOfOne, it still showing the old initialized value (10) which I am really confused. I have printed the address of class One object in this directValOfOne funtion and it shows same. If so then why the new value(220) is not updated here.
Source code is placed below.
#include <iostream>
using namespace std;
class One{
int _x;
public:
One(int a):_x{a} {}
//setters and getters
void setDataOne(int a) { _x = a; }
int getDataOne() const { return _x; }
//print values
void printOne() { cout<<"_x - "<<_x<<endl; }
friend class Two;
};
class Two{
One _a;
int id_one = 0;
public:
Two(One a):_a{a} {}
//setters and getters
void setDataTwo(int a) { }
int getDataTwo(One *obj) {
id_one = obj->getDataOne();
return id_one;
}
void printTwo() { printf("id_one = %d\n",id_one); }
void directValOfOne() {
printf("address = %p\n",&_a);
printf("_a._x = %d\n",_a._x);
}
};
int main(){
One one(10);
Two two(one);
one.printOne();
two.getDataTwo(&one);
two.printTwo();
two.directValOfOne();
printf(" *********** \n");
one.setDataOne(222);
one.printOne();
two.getDataTwo(&one);
two.printTwo();
two.directValOfOne();
return 0;
}
and the console output is,
_x - 10
id_one = 10
address = 006dfee4
_a._x = 10
***********
_x - 222
id_one = 222
address = 006dfee4
_a._x = 10
As you can see the _a._x still prints the value 10. But actually the _x is updated to new value 220. Sorry if I explained it so detail. Just to give you an overview I detailed like this.
So my que is ,
Why it is not showing the updated value since the addresses are same?
Am I missing any important concept here ? If so please guide me to understand this problem.
The problem in your code is that you pass to Two an instance of class One by value. This means that Two stores a copy of the instance of One you pass to it. When you change the value of _x in one it does not affect the value of _x in _a (inside two).
In order for your code to work you need to pass a reference to One in Two's constructor and store this reference. Now every change to one will also affect _a.
Modified code:
class Two{
One& _a;
int id_one = 0;
public:
Two(One& a):_a(a) {}
// ...
Regarding the address issue, the address of _a will stay the same since there's no reason for it to change once initialized. If you'll print the address of one in your current code (before the suggested modifications) it should be in a different address than _a (since _a is a copy that's located somewhere else).
In the modified version of the code you should see the same address since it's the same object.
So basically, I want my first class to be a basic one, just like in the example down below, to be inherited, and the child classes which come out of it, to have a same named function, that will return the fictional price of something, but I don't know how to access the functions while writing a void function out of classes, which recieves an array of pointers of the basic class and then the number of array elements, then calls for the same named function in both child classes.
Take a look yourself.
While you're at it, feel free to tell me any errors I've made along the way, regards!
#include <iostream>
#include <cstring>
#include <ctype.h>
using namespace std;
class basic{
protected:
char name[20];
public:
basic(char * n)
{
strcpy(name,n);
}
};
class advanced1:public basic{
protected:
float price;
public:
advanced1(char * n, float p):basic(n)
{
price=p;
}
float priced()
{
if(price<10)
return price*1.5;
else
return price*1.2;
}
};
class advanced2:public basic{
protected:
float price;
public:
advanced2(char * n, float p):basic(n)
{
price=p;
}
float priced()
{
if(price<15)
return price*2.3;
else
return price*1.8;
}
};
void printstuff(basic *basics[], int basicsN)
{
for(int i=0;i<basicsN;i++)
{
cout<<basics[i]->priced();
}
}
What you are describing is a "virtual" function. You can follow this tutorial.
Looking at your code, it seems like you don't actually want the base class to implement the function. For that you'd have to use a pure virtual function - see this link. But keep in mind that using a pure virtual function means that you cannot directly instantiate the base class.
And about errors, just on first glance, the way you use strcpy could write beyond the end of the name array. I recommend using strncpy (see this) instead and specifying the number of characters. If you want to copy exactly 20 characters always, you could specify 20, or if 20 is just the limit, you could use strlen to get the length of the incoming string and then copy std::min(20, length) characters.
The following is directly related to this. What I would like is to be able to call and have active only one class at a time, to save memory, but also because I plan to add, later on, a GUI, so I'd be able to call the classes through a drop-down menu (for example).
I tried making composition, and this is what came out:
#include <iostream>
class Power
{
private:
double m_x;
public:
Power() {std::cout<<"Power\n";}
Power(double x): m_x {x} {std::cout<<"Power("<<x<<")\n";}
~Power() {std::cout<<"~Power\n";}
const double getX() const { return m_x; }
};
class Scanner
{
private:
Power m_power;
public:
Scanner() {std::cout<<"Scanner\n";}
Scanner(const Power &p): m_power {p} {std::cout<<"Scanner("<<&p<<")\n";}
void print() {std::cout<<"x="<<m_power.getX()<<'\n';}
};
class Printer
{
private:
Power m_power;
public:
Printer() {std::cout<<"Printer\n";}
Printer(const Power &p): m_power {p} {std::cout<<"Printer("<<&p<<")\n";}
void print() {std::cout<<"x="<<m_power.getX()<<'\n';}
};
class Copier // if Copier is to be used for "unification", will "public" be needed?
{
private:
Scanner *m_s;
Printer *m_p;
int m_i;
public:
Copier() {std::cout<<"Copier\n";}
Copier(const Power &p, int i): m_i {i}
{
if (i)
m_s = new Scanner(p);
else
m_p = new Printer(p);
std::cout<<"Copier("<<&p<<","<<i<<")\n";
}
void print() { std::cout << (m_i ? m_s->getX() : m_p->getX()) << '\n'; }
};
int main(int argc, char *argv[])
{
Scanner *s {new Scanner(Power(2.3))};
s->print();
Printer *p {new Printer(Power(3.14))};
p->print();
s->print(); // here, both *s and *p exist, both use memory
// this comes after considering adding class Copier
Copier *c {new Copier(Power(1.618), 0)};
c->print();
c = new Copier(Power(2.718), 1);
c->print();
return 0;
}
Ignore Copier for a bit. As it is, I can use it, and this is what comes out:
Power(2.3)
Scanner(0x7ffc80d98c10)
~Power
x=2.3
Power(3.14)
Printer(0x7ffc80d98c20)
~Power
x=3.14
x=2.3
The (major) problem now is that there are multiple objects in memory, there's *s and there's *p, as you can see x can pe printed out with both 3.14 and 2.3. If I have more than 2 classes (which I do), I could call each class and each will take up memory. That's not something I want.
How can I call only one class at a time and not have to call extra resets or deletes? I thought of adding another class for it, see Copier. But I can't use std::unique_ptr and the solution in the code is, not only extremely ugly, but doesn't even work. Plus it calls constructors like crazy.
I tried using std::unique_ptr in a simple function, with std::make_unique (that needs c++14, and I'd rather keep some larger safety margin, but I could also live with it, too). It also doesn't work because it points to Power (if I call z->print() it says 'class Power' has no member 'print'):
std::unique_ptr<Power> call(const Power &p, const int &i)
{
if (i)
return std::make_unique<Printer>(p);
else
return std::make_unique<Scanner>(p);
}
I don't know how to make this. In short, classes Scanner, Printer, and any other that exist, are dedicated classes that perfom one task, only, unique in their way of computing, and all of them make use of some common variables in Power (besides their own). I don't think it would be very effective to move the common variables to each class because they would only bloat the code, and, as I understand it, "if you can use a storage class instead of repeating the same variable over and over, use it" (not my words, is this true?). Then, I'd like to be able to instantiate those classes, but only have one active at a time, to spare memory.
As an example, suppose one class makes an array of 1mil values, then another makes 1mil different values, and so on. Imagine having that array in memory as many times as there are instantiated classes. I don't want that. The purpose of Copier would have been to call (based on the conditional) only one class at a time. Job done? Call another, but forget anything else that was done before, start anew. And all this to be able to call through only one widget, such as select from list, click&go, that will be added later.
That was a stupid mistake, I forgot to delete public ... after copy-pasting. I also tried the code now (with Copier), it compiles, but still doesn't work, m_x stays empty, even with the very ugly solution of having two Scanner and Printer pointers as member variables inside Copier.
Well, after some tries, I couldn't make what I wanted so I thought to go back to my original idea, even if it meant inheritance. So I came up with this piece of code, where I changed the names to make a bit more sense(?):
#include <iostream>
class Garage
{
protected:
double m_x; // gas, tires, etc, that all cars use, reside in the Garage
public:
Garage() {std::cout<<"Garage\n";}
virtual ~Garage() {std::cout<<"~Garage\n";}
};
class Audi: virtual public Garage
{
public:
Audi() {std::cout<<"Audi\n";}
void f(const double &x) { m_x=x; std::cout<<"Audi::f("<<x<<")\n";}
};
class Bmw: virtual public Garage
{
public:
Bmw() {std::cout<<"Bmw\n";}
void f(const double &x) { m_x=x; std::cout<<"Bmw::f("<<x<<")\n";}
};
class Driver: public Audi, public Bmw
{
private:
double m_y; // report of driving, based on m_x
public:
Driver() {std::cout<<"Driver\n";}
Driver(const double &x, int i)
{
if (i)
Bmw::f(x);
else
Audi::f(x);
m_y = -m_x;
std::cout<<"Driver("<<x<<","<<i<<")\n";
}
void print() { std::cout << "x=" << m_x << ", y=" << m_y << '\n'; }
};
int main(int argc, char *argv[])
{
Driver *d {new Driver(1.618, 0)};
d->print();
d = new Driver(0.618, 1);
d->print();
// even iteration works now
delete d;
d = nullptr; // to be sure it's dead(?)
for (int i=0; i<2; ++i)
{
d = new Driver(3.14, i);
d->print();
}
return 0;
}
Now, this works, but I have a feeling I set a new record on bad code example. Please don't bash me for this, rather point out all the mistakes, or how you would do it to achieve the same result. Still, even if it seems to work as I want, it still calls all the constructors, on all branches, instead of only on the needed ones. I realize (my apologies) I forgot to say that Driver, here, is also responsible for using m_x further, for its m_y (that's why the code is a bit different).
I'd like to point out that I am not fixed in keeping this code, or any other, I am willing to change and adapt, as long as I reach my purpose. But since I am a beginner, I can't make too many combinations, so I am left with presenting whichever result it is that I reached to try and make myself understood. The program above, as it is, when run, gives what I want, even has the possibility of making a loop, which will let me use it much easier in a GUI, later on. The names, as they are, make the most sense in composition, Garage has-a Bmw, and that was what I tried, but I couldn't obtain what I wanted. So, even if this uses inheritance and does not make sense that an Audi is-a Garage, I kept the names to suggest my initial tryout with composition. My main reason for posting this is to show what I would like the program to do. What happens in main() will be used in a GUI, I am thinking of Qt, because I'd like this to run on all 3 major OSes. So having the possibility of calling one car at a time, using it, and also being able to store previous information without having stale objects in memory, only m_x*nr_of_cars, will make it much easier to work with.
Here is one way to do it.
{ // scope begins
Printer p; // note, no pointers
p.print();
} // scope ends, p is gone
Here we have an object that appears, does one thing once, and disappears.
Here is another
boost::variant<Printer,Scaner,Copier> psc(Printer());
psc.get<Printer>().print();
psc = Scaner(); // the printer is gone
Use some std::unique_ptr constructor:
std::unique_ptr<Power>
call(const Power &p, const int &i) {
if (i)
return std::unique_ptr<Power>(new Printer(p));
else
return std::unique_ptr<Power>(new Scanner(p));
}
Perhaps what you really want is a tagged union. Follow the rule of five. See this for inspiration.
I have four .cpp files, Animal, Cattle, Sheep, DrugAdmin.
Animal is parent class of Cattle, and it has calcDose(), which calculates the amount of dose. DrugAdmin is main function.
The thing is, I want to use calcDose() function differently (Cattle, Sheep) and no calcDose() function is needed for Animal class. However, every time I try to use calcDose(), it automatically calls function in Animal class even when I want to use under Cattle class. This is the code I have done so far. (I've cut it down)
Animal.cpp
#include "Animal.h"
#include <string>
using namespace std;
Animal::Animal(int newid, double newweight, int yy, int mm, int dd, char newsex, vector<Treatment> treatArray)
{
id = newid;
weight = newweight;
yy = yy;
mm = mm;
dd = dd;
accDose = 0;
sex = newsex;
}
double Animal::calcDose(){
return 0;
}
Cattle.cpp
#include "Cattle.h"
using namespace std;
Cattle::Cattle(int newid, double newweight, int yy, int mm, int dd,
char newsex, vector<Treatment> newtreatArray, string newcategory)
: Animal(newid, newweight, yy,mm,dd, newsex, newtreatArray)
{
id = newid;
weight = newweight;
accDose = 0;
sex = newsex;
Cattle::category = newcategory;
}
Cattle::~Cattle(){}
double Cattle::calcDose(){
if(getDaysDifference() < 90 || getCategory() == "Meat"){
accDose = 0;
return accDose;
}
else if(getCategory() == "Dairy"){
if (weight < 250 || accDose > 200){
accDose = 0;
}
else{
accDose = weight * 0.013 + 46;
}
return accDose;
}
else if(getCategory() == "Breeding"){
if (weight < 250 || accDose > 250){
accDose = 0;
}
else{
accDose = weight * 0.021 + 81;
}
return accDose;
}
else
{
//cout << "It is not valid category" << endl;
}
}
Sheep class is pretty much same but the contents of calcDose()
DrugAdmin.cpp
#include "DrugAdmin.h"
using namespace std;
vector<Animal*> vec_Animal;
void addAnimal(){
int select=0;
int id;
double weight;
int yy;
int mm;
int dd;
char sex;
string category;
vector<Treatment> treatArray;
//user inputs all the values (i've cut it down)
Animal* c1 = new Cattle(id,weight,yy,mm,dd,sex,treatArray,category);
vec_Animal.push_back(c1);
}
void administerDose(int id) //Main Problem
{
vector<Animal*>::iterator ite_Animal = vec_Animal.begin();
for(ite_Animal; ite_Animal != vec_Animal.end(); ++ite_Animal)
cout<<"\nVector contains:"<< (*ite_Animal)->calcDose();
}
I'm sorry for the long and messed up question. Final question is, Cattle has extra data member which is category but the system doesn't recognise this as well. It recognises as if it is Animal object. Can I have a piece of advice please?
Cheers
every time I try to use calcDose(), it automatically calls function in Animal class
Sounds like you forgot to make calcDose a virtual member function.
Final question is, Cattle has extra data member which is category but the system doesn't recognise this as well. It recognises as if it is Animal object.
I'm not sure what you mean by the "system" "recognizing" anything, but if you access a Cattle object through an Animal*, then you can't get to the Cattle-specific members. You'd have use either a Cattle* or, again, polymorphism/virtual.
Unlike Java (and many other languages), C++ uses what is called "static binding" by default. Static binding means the function called is based on the declared type of the object (or pointer) at compile time, rather than what the object actually is (or what the pointer is actually pointing to).
The alternative to static binding is "dynamic binding". In dynamic binding, the function called is based on what the object actually is (or what the pointer is actually pointing to) at runtime.
To enable dynamic binding, which is what you'll want if you have an inheritance hierarchy set up and are maintaining base class pointers (Animal*s), you have to use the keyword virtual. virtual makes a function dynamically bound, so that calls to that function will reflect the actual runtime type of the object (Cattle) rather than the compile time declared pointer type (Animal*).
To declare a function virtual, you put the virtual keyword before the return value on the function declaration (in the class declaration / .h file):
class Animal
{
virtual void calcDose();
// ...
};
It is also good style to put virtual on the overridden function in the derived class (calcDose() in Cattle), although the virtual is implied for inherited functions, so putting it there is not strictly necessary.
The one last thing to make sure you to get dynamic binding, is to make sure you always have pointers (or references) to objects rather than objects on the stack (when you want dynamic binding). An object on the stack (i.e. Animal a) can only be it's declared type, it can't point to a derived class type. So the vector<Animal*> you have is perfect, because those pointers can point to Cattle objects (or Animal objects), while a vector could only hold actual animal objects.
You should make your calcDose function virtual and redefine it in each subclass: Cattle, etc. Also to recognize your Animal as a Cattle you have to cast it to Cattle class. But you are supposed to use the common base type interface most of the time.
Using C++ I built a Class that has many setter functions, as well as various functions that may be called in a row during runtime.
So I end up with code that looks like:
A* a = new A();
a->setA();
a->setB();
a->setC();
...
a->doA();
a->doB();
Not, that this is bad, but I don't like typing "a->" over and over again.
So I rewrote my class definitions to look like:
class A{
public:
A();
virtual ~A();
A* setA();
A* setB();
A* setC();
A* doA();
A* doB();
// other functions
private:
// vars
};
So then I could init my class like: (method 1)
A* a = new A();
a->setA()->setB()->setC();
...
a->doA()->doB();
(which I prefer as it is easier to write)
To give a more precise implementation of this you can see my SDL Sprite C++ Class I wrote at http://ken-soft.com/?p=234
Everything seems to work just fine. However, I would be interested in any feedback to this approach.
I have noticed One problem. If i init My class like: (method 2)
A a = A();
a.setA()->setB()->setC();
...
a.doA()->doB();
Then I have various memory issues and sometimes things don't work as they should (You can see this by changing how i init all Sprite objects in main.cpp of my Sprite Demo).
Is that normal? Or should the behavior be the same?
Edit the setters are primarily to make my life easier in initialization. My main question is way method 1 and method 2 behave different for me?
Edit: Here's an example getter and setter:
Sprite* Sprite::setSpeed(int i) {
speed = i;
return this;
}
int Sprite::getSpeed() {
return speed;
}
One note unrelated to your question, the statement A a = A(); probably isn't doing what you expect. In C++, objects aren't reference types that default to null, so this statement is almost never correct. You probably want just A a;
A a creates a new instance of A, but the = A() part invokes A's copy constructor with a temporary default constructed A. If you had done just A a; it would have just created a new instance of A using the default constructor.
If you don't explicitly implement your own copy constructor for a class, the compiler will create one for you. The compiler created copy constructor will just make a carbon copy of the other object's data; this means that if you have any pointers, it won't copy the data pointed to.
So, essentially, that line is creating a new instance of A, then constructing another temporary instance of A with the default constructor, then copying the temporary A to the new A, then destructing the temporary A. If the temporary A is acquiring resources in it's constructor and de-allocating them in it's destructor, you could run into issues where your object is trying to use data that has already been deallocated, which is undefined behavior.
Take this code for example:
struct A {
A() {
myData = new int;
std::cout << "Allocated int at " << myData << std::endl;
}
~A() {
delete myData;
std::cout << "Deallocated int at " << myData << std::endl;
}
int* myData;
};
A a = A();
cout << "a.myData points to " << a.myData << std::endl;
The output will look something like:
Allocated int at 0x9FB7128
Deallocated int at 0x9FB7128
a.myData points to 0x9FB7128
As you can see, a.myData is pointing to an address that has already been deallocated. If you attempt to use the data it points to, you could be accessing completely invalid data, or even the data of some other object that took it's place in memory. And then once your a goes out of scope, it will attempt to delete the data a second time, which will cause more problems.
What you have implemented there is called fluent interface. I have mostly encountered them in scripting languages, but there is no reason you can't use in C++.
If you really, really hate calling lots of set functions, one after the other, then you may enjoy the following code, For most people, this is way overkill for the 'problem' solved.
This code demonstrates how to create a set function that can accept set classes of any number in any order.
#include "stdafx.h"
#include <stdarg.h>
// Base class for all setter classes
class cSetterBase
{
public:
// the type of setter
int myType;
// a union capable of storing any kind of data that will be required
union data_t {
int i;
float f;
double d;
} myValue;
cSetterBase( int t ) : myType( t ) {}
};
// Base class for float valued setter functions
class cSetterFloatBase : public cSetterBase
{
public:
cSetterFloatBase( int t, float v ) :
cSetterBase( t )
{ myValue.f = v; }
};
// A couple of sample setter classes with float values
class cSetterA : public cSetterFloatBase
{
public:
cSetterA( float v ) :
cSetterFloatBase( 1, v )
{}
};
// A couple of sample setter classes with float values
class cSetterB : public cSetterFloatBase
{
public:
cSetterB( float v ) :
cSetterFloatBase( 2, v )
{}
};
// this is the class that actually does something useful
class cUseful
{
public:
// set attributes using any number of setter classes of any kind
void Set( int count, ... );
// the attributes to be set
float A, B;
};
// set attributes using any setter classes
void cUseful::Set( int count, ... )
{
va_list vl;
va_start( vl, count );
for( int kv=0; kv < count; kv++ ) {
cSetterBase s = va_arg( vl, cSetterBase );
cSetterBase * ps = &s;
switch( ps->myType ) {
case 1:
A = ((cSetterA*)ps)->myValue.f; break;
case 2:
B = ((cSetterB*)ps)->myValue.f; break;
}
}
va_end(vl);
}
int _tmain(int argc, _TCHAR* argv[])
{
cUseful U;
U.Set( 2, cSetterB( 47.5 ), cSetterA( 23 ) );
printf("A = %f B = %f\n",U.A, U.B );
return 0;
}
You may consider the ConstrOpt paradigm. I first heard about this when reading the XML-RPC C/C++ lib documentation here: http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#constropt
Basically the idea is similar to yours, but the "ConstrOpt" paradigm uses a subclass of the one you want to instantiate. This subclass is then instantiated on the stack with default options and then the relevant parameters are set with the "reference-chain" in the same way as you do.
The constructor of the real class then uses the constrOpt class as the only constructor parameter.
This is not the most efficient solution, but can help to get a clear and safe API design.