I am trying to use a class that I have written in another class. The problem is I am having difficulty using anything but the default parameters/constructor from the original class.
I have simplified the classes below to show what I am trying to achieve (I have tried all the variations on this I could think of but I think fundamentally I do not understand what's going on).
When I call class_two through class_one I want to use my own values for the calculation. However when I try this I just get the default parameters written in class_two.
class class_one {
private:
double a;
class_two class2;
public:
class_one(double A = 0.5, double B = 0.2) {
a = A;
class2 = class_two(b);
}
double calculation(){
return A*class2.get_b();
}
}
Where class_two would be,
class class_two {
private:
double b;
public:
class_two(double B = 0.5){
b = B;
}
double get_b(){
return b;
}
}
Example of what I am trying to run,
class_one().calculation();
actual output: A*B = 0.5 * 0.5 (Where the B values comes from class_two)
desired output: A*B = 0.5 * 0.2 (Where the B values comes from class_one)
Apologies this seems like a super simple question but I cannot get it to work!
When the constructor of a class is called, then - before its body starts executing - all of its data members are initialized. That means that for `class_two, the default constructor is called for its creation, since you don't say anything different.
In order to achieve your goal, use an initialization list, like this:
class_one(double A = 0.5, double B = 0.2) : a(A), class_two(B) {
// leave it empty in this case
}
PS: I initialized a via the initializer list as well, which is unrelated to your question, but a good habit to have, since initialization of data members is usually done via the initialization list, and not in the body of the constructor itself.
My mistake was very dum and not very interesting.
Basically I was using class2 to assign variables but I was only reassigning class2 after I had done this. I hadn't realised this.
Thanks Holt for showing me that my problem was not where I thought it was and gsamaras and François Andrieux for explaining that it's best to use an initialization list for this scenario!
class class_one {
private:
double a;
class_two class2;
public:
class_one(double A = 0.5, double B = 0.2) {
a = A*set_a();
class2 = class_two(b);
}
double set_a(){
return class2.some_function();
}
double calculation(){
return A*class2.get_b();
}
}
Related
I'm trying to create an abstract class for ordinary differential equations, and have its independent variable use a different name in the inheriting classes. How do I go about that?
I don't want to allocate more memory for the renaming of the variable, i.e. create a new variable or a pointer to the base variable, as that's counterproductive. I just want to be able to access it with a different name in my inheriting classes, so that it's easier to know what the independent variable represents.
Mayhap a better question is, does the functionality of variable name overriding even exist in C++?
To give some code:
class ODE {
private:
int numEqns
double* q; // dependent variables
public:
double s; // independent variable
ODE(int numEqns) {
this->numEqns = numEqns;
this->q = new double[numEqns];
}
SetQOfIdxTo(int idx, double val) {
this->q[idx] = val;
}
};
class SpringODE : public ODE {
public:
double mass;
double c; // damping coefficient
double k; // spring constant
double d0; // initial deflection
SpringODE(double mass, double c, double k, double d0) : ODE(2) {
this->mass = mass;
this->c = c;
this->k = k;
this->d0 = d0;
time = 0.0;
SetQOfIdxTo(0, 0.0);
SetQOfIdxTo(1, d0);
}
};
The code is based on the one given in Grant Palmer's book "Physics for Game Programmers". The book in question being why I'm asking this question, as out of nowhere the time variable's Get function returns the base classes' GetS() function, which just returns "s" (albeit the code in the book is written in Java).
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.
I'll try to make this as concise as possible and while I understand that these questions can be considered "basic" I have already looked at websites such as cplusplus.com and yolinux tutorials but i need somebody to explain this to me like I have just had a major head trauma..
1)
class Rectangle {
private:
int lineNumber; // LineNumber of the ACSIL Tool
float valueMax; // value of the higher limit of the rectangle
float valueMin; // value of the lower limit of the rectangle
public:
Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin);
int getLineNumber();
float getValueMax();
float getValueMin();
};
So int linenumber, valueMax and ValueMin are declared private members and thus are only accessible by members of the same class, thats fine. But what about the part that follows the "public:" ?
a) Is Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin); a function that is being overloaded? and if yes are int getLineNumber() etc part of that function or seperate members of the public part of the class?
2)
Rectangle::Rectangle(SCStudyInterfaceRef sc, int lineNumber0, float value1, float value2) {
lineNumber = lineNumber0;
int value2_greater_than_value1 = sc.FormattedEvaluate(value2, sc.BaseGraphValueFormat, GREATER_OPERATOR, value1, sc.BaseGraphValueFormat);
if (value2_greater_than_value1 == 1) {
valueMax = value2;
valueMin = value1;
} else {
valueMax = value1;
valueMin = value2;
}
}
int Rectangle::getLineNumber() {
return lineNumber;
}
float Rectangle::getValueMax() {
return valueMax;
}
float Rectangle::getValueMin() {
return valueMin;
}
a) I'm pretty sure that the functions defined inside the public part of the rectangle class are being "defined" here, or something along those lines.
b) I am really confused about what is happening here on the Rectangle::Rectangle(SCStudyInterfaceRef sc, int linenumber0, float value1, float value2) part. I understand the logic of what is happening within the function itself but i am confused about the paramters being input within the " ( ) " and how exactly this relates to what happenes inside the class public part. This really is the most important question that needs answering.
I have tried to be as concise and onpoint as possible, would appreciate some help in understanding this syntax.
Question 1
It's a constructor with 4 parameters.
int getLineNumber();
float getValueMax();
float getValueMin();
are all member functions in the class.
Question 2
The constructor defined earlier is called with 4 parameters. If no other constructor is defined then you'll have to instantiate the class with exactly 4 parameters, i.e:
Rectangle *rect = new Rectangle(sc, 100, 1.2, 6.8);
or simply:
Rectangle rect(sc, 100, 1.2, 6.8);
These parameteres are then used to "set the object in an initial state".
The member functions are used to get various values in their current (or final or only) state.
Rectangle::Rectangle is the class constructor. It is called whenever a Rectangle object is created. Read about constructors to understand better.
The constructor is setting initial values for the valueMax and valueMin member variables. It uses the parameters passed to the constructor to do this. Read about function parameters to understand better.
1) a: If no ctor function is declared, then the compiler writes a ctor for the class. But when a ctor is provided by the class no default ctor is written by the class and hence no overloading is taking place. Now if you go on and define one more ctor, may be because you want the object to be constructed in some other way, then you will have an overloaded ctor. In your case no overloading is taking place.
int getLineNumber() is just another member of the class.
2)
a: You are correct.
b: The parameters put inside "( )" are arguments list and if this function is called somewhere, then this list is type-matched and then function is called(in case of overloading). Now if you write a statement like:
Rectangle x(a, b, c, d);
then it means that your sc=a, lineNumber0=b, value1=c, value2=d for this function call.
I have this definition for my structure:
struct localframevelo
{
double ivelo; //i(x) component of velocity
double cvelo; //c(y) component of velocity
double rvelo; //r(z) component of velocity
double speed; //total magnitude of velocity
localframevelo()
{
ivelo = 0;
cvelo = 0;
rvelo = 0;
speed = 0;
}
localframevelo(double init_ivelo, double init_cvelo, double init_rvelo)
{
ivelo = init_ivelo;
cvelo = init_cvelo;
rvelo = init_rvelo;
speed = sqrt(pow(ivelo, 2.0) + pow(cvelo, 2.0) + pow(rvelo, 2.0));
}
};
Here is a class that I am trying to use the default constructor of localframevelo in:
class missionprofile
{
//misison waypoints structure************************
private:
double stdholdtime; // 0.25 second within tolerance radius to "reach" a waypoint
double stdtolrad; // 0.5 meter tolerance radius (error magnitude) to "be at" a waypoint
localframevelo stdvelo;
waypoint missionwaypoints[MAXLISTLENGTH];
int numwaypoints;
public:
missionprofile();
missionprofile(int points, double StdHoldTime, double StdTolRadius, localframevelo StdVelo);
};
Here is the implementation of the default constructor for the class that I am trying to call the localframevelo's default constructor:
missionprofile::missionprofile()
{
numwaypoints = 0;
stdholdtime = 0;
stdtolrad = 0;
stdvelo(); //ERROR
}
I get this error: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type. I am using the mbed compiler, what is wrong with my code?
You can safely remove this line:
stdvelo();
In the context of a function body, this is interpreted as a call to the operator()() of an instance of localframevelo, not an initialization. The data member will be default constructed anyway without any explicit initialization. But what you should really be doing is to initialize your data members in the constructor's initialization list:
missionprofile::missionprofile()
: numwaypoints(),
stdholdtime(),
stdtolrad(),
stdvelo()
{
}
And similarly for localframevelo's constructors and the other missionprofile constructor.
When you write stdvelo(), the compiler sees stdvelo.operator()() and then complains when no such function exists.
The data member is going to be constructed anyway; you don't need the line at all.
Also, it's marginally faster to use initialization rather than assignment for your starting values (though chances are high that your compiler will optimize away the difference anyway).
So you'd use this, for example, for the second constructor:
localframevelo(double init_ivelo, double init_cvelo, double init_rvelo)
: ivelo(init_velo)
, cvelo(init_cvelo)
, rvelo(init_rvelo)
, speed(sqrt(pow(ivelo, 2.0) + pow(cvelo, 2.0) + pow(rvelo, 2.0)))
{}
For the first, you'd just use 0 instead of init_velo et al.
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.