Here is the problem:
Write three base class named Voltmeter, Ammeter and ResistanceMeter.
Voltmeter class will have a member function volt, a non default constructor, a copy constructor
and a function measureVolt().
Ammeter class will have a member function amp, non default constructor, a copy constructor and
a function measureCurrent().
ResistanceMeter class will have a member function resistance, non default constructor,
a copy constructor and a function measureResistance().
Now write a class Multimeter which will
have object of Voltmeter, Ammeter and ResistanceMeter so thus it can use the functionality of those class.
In my solution, the compiler say undefined reference on every object I used in the class 'multimeter'. Code is as below:
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
class voltmeter{ //class - Voltmeter
float volt;
public:
voltmeter(); //default constructor
voltmeter(float v){ //non default constructor
volt = v;
}
voltmeter(voltmeter &ob) //copy constructor
{
volt = ob.volt;
}
void set_volt(float v)
{
volt = v;
}
float get_volt(void)
{
return volt;
}
void measure_volt(void) //measureVolt()
{
cout<<"Current volt in the circuit is: "<<volt<<"V"<<endl;
}
};
class ameter
{
float amp;
public:
ameter();
ameter(float a)
{
amp = a;
}
ameter(ameter &ob)
{
amp = ob.amp;
}
void measure_current(void)
{
cout<<"Current flow in circuit is: "<<amp<<"amp"<<endl;
}
void set_amp(float a)
{
amp = a;
}
float get_amp(void)
{
return amp;
}
};
class res_meter //class - resistanceMeter
{
float resistance;
public:
res_meter();
res_meter(float res)
{
resistance = res;
}
res_meter(res_meter &ob)
{
resistance = ob.resistance;
}
float get_resistance(void)
{
return resistance;
}
void set_resistance(float res)
{
resistance = res;
}
void meas_res(void)
{
cout<<"Current resistance in circuit is "<<resistance<<"ohm"<<endl;
}
};
class multimeter
{
res_meter r1;
ameter a1;
voltmeter v1;
public:
multimeter(){
r1.set_resistance(12.30);
a1.set_amp(22.5);
v1.set_volt(26.9);
}
// ~multimeter();
void show_info(void)
{
cout<<"Current Multimeter Status is as below: "<<endl;
a1.measure_current();
r1.meas_res();
v1.measure_volt();
}
};
int main()
{
multimeter M;
M.show_info();
return 0;
}
You declare a default constructor for all the classes (which is used in the multimeter class), but you never define the constructors.
Change e.g.:
class voltmeter
{
// ...
voltmeter();
// ...
};
to
class voltmeter
{
// ...
voltmeter() {}
// ...
};
In my solution, the compiler say undefined reference on every object I used in the class 'multimeter'.
Read your warning messages more carefully. The compiler is telling you that the multimeter default constructor (which is defined) is referencing the default constructors for classes ameter, res_meter, and voltmeter'. It is those default constructors that aren't defined.
So define them, or use the non-default constructors that you did define.
Related
I have created 3 classes: Auto (means "car"), Klant (means "customer") and AutoVerhuur (means "car dealership).
In my main(), I have created Auto and Klant objects, and am trying to create an AutoVerhuur object.
In this last class, I basically want to reference to a specifc Klant and Auto (which customer rented which car). But, when I try that, I get an error:
error: no matching function for call to 'Auto::Auto()'
How do I correctly reference other objects in my object?
Here is my code, if you want to take a look:
#include <iostream>
using namespace std;
class Auto{
private:
string type;
double prijs_per_dag;
public:
Auto(string type, double prijs_per_dag){
this->type = type;
this->prijs_per_dag = prijs_per_dag;
}
void set_prijs_per_dag(double percentage){
this->prijs_per_dag = percentage;
}
double get_prijs_per_dag(){
return prijs_per_dag;
}
};
class Klant{
private:
string naam;
double korting_percentage;
public:
Klant(string naam):
naam(naam){}
void set_korting(double percentage){
this->korting_percentage = percentage;
}
double get_korting(){
return this->korting_percentage;
}
string get_name(){
return naam;
}
void set_name(string naam){
this->naam = naam;
}
};
class AutoHuur{
private:
int aantal_dagen;
Auto wagen;
Klant huur;
public:
AutoHuur(Auto car, Klant huurder, int dagen){
wagen = car;
huur = huurder;
aantal_dagen = dagen;
}
};
int main(){
Klant k("Mijnheer de Vries");
k.set_korting(10.0);
Auto a1("Peugeot 207", 50);
AutoHuur ah1(a1, k, 4);
}
Your Auto class does not have a default constructor defined, but your AutoHuur class has an Auto wagen; data member which the compiler is trying to default-construct (because you haven't told it otherwise), hence the error.
So, you need to either:
give the Auto class a default constructor, eg:
Auto(){
this->type = "";
this->prijs_per_dag = 0;
// or whatever default values make sense for your needs...
}
Otherwise, change the constructor of the AutoHuur class to use its member initialization list to construct the wagen member using the desired Auto constructor (you should do the same for the other data members, too), eg:
AutoHuur(Auto car, Klant huurder, int dagen)
: wagen(car), huur(huurder), aantal_dagen(dagen)
{
}
Please I am trying to print out the value of a nested class from the private access specifier.
#include <iostream>
#include <cstdlib>
using namespace std;
class cal{
private:
int a = 0;
public:
int setNum(int m){
a = m;
}
void getNum(){
cout<<"the number is: "<<a<<endl;
}
class area{
public:
int setMan(int z){
cal obj;
obj.setNum(z);
return 1;
}
};
};
int main(){
cal::area obj2;
obj2.setMan(200);
cal obj3;
obj3.getNum();
'
return 0;
}
cal::area obj2;
obj2.setMan(200); is to set 200 to the nested class area and into the function setMan, of which setMan which pass the same value to the int setNum(int m){a = m;} this will set the value of a to "200". Then I wanted to print out the value of a but it displays 0 instead of 200.
Defining a nested class only provides a definition for a nested class. If you want to have a member of that class you have to declare it:
struct cal {
struct area {}; // class definition
area m_area; // member
};
int setMan(int z){
cal obj;
obj.setNum(z);
return 1;
}
The object obj is a temporary auto object and would be destroyed when you return from the function. By the way, "set" functions should not return values, returning 1 is confusing.
If you wish to connect objects somehow consider the composition or aggregation. For example:
// ...
class area{
public:
area(cal& obj) : obj(obj);
int setMan(int z){
obj.setNum(z);
return 1;
}
cal &obj;
};
// ...
int main(){
cal obj;
cal::area obj2(obj);
obj2.setMan(200);
obj.getNum();
return 0;
}
Anyway, that is just an artificial example, I don't see the reason you make area a nested class, the reason of setting values to cal from area, etc.
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 wonder if there is a workaround is such situation:
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
}
//...
A a; //crash
//...
I suppose it is caused by order of initialization. Variable B is initilized by calling an uninitilized std::function instance, hence the crash. By my logic, the workaround would be to initialize std::function first, then initialize member B. But then, such code is not valid:
class A
{
//error: 'B' was not declared in this scope
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
}
I tried to make to make the std::function static, and such code works, but requires non-constexpr/const member, because std::function has non-trivial destructor - which is bad, because that requires source file, which requires creating such file, which requires some efford and destruction of my beautiful header-only class hierarchy! (I mean, I could be lazy and define this variable in the header, but then the multiple definition problem occurs). I know it might be a bad design (i'm just testing things out), but do you have any ideas how the problem can be solved without involving source files?
Although your example is contrived, there are times when I've needed (or its more convenient) to initialize complex objects in a similar way.
But, why use std::function<>? Why not just use a function?
class A
{
class
{
public:
void setValue(int val) { i = val; }
private:
int i;
} B = initB(10);
static decltype(B) initB(int value)
{
decltype(B) temp;
temp.setValue(value);
return temp;
}
};
Although, I wouldn't normally use decltype(B); I would just give the class a name.
I feel like I am somehow subverting your intent, but if you initialize the variables in the constructor, you can make things work.
#include <functional>
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B;
std::function<decltype(B)(int)> initB;
public:
A() {
initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
B = initB(10);
}
};
int main() {
A a;
}
A::initB is a value. It's not initialized at the point where you call it, because initialization is done (loosely speaking) in the order you specify member fields. You can verify this by executing the below, which works:
#include <iostream>
#include <functional>
using namespace std;
template<typename T, typename U>
T set(T& tgt, const U& src)
{
new(&tgt) T(src);
return tgt;
}
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = set(initB, [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;})(10);
std::function<decltype(B)(int)> initB;
};
int main() {
A a;
}
I have my main.cpp like this:
#include <iostream>
#include "curve1.h"
#include "curve2.h"
using namespace std;
int main()
{
Curve1 curve1Obj;
Curve2 curve2Obj;
curve1Obj.enterScores();
curve1Obj.calcAverage();
curve1Obj.output();
curve1Obj.curve();
curve1Obj.output(curve1Obj.new_getAverage1(), curve1Obj.new_getScore1());
curve2Obj.curve();
return 0;
}
Base class Score has two derived classes Curve1 and Curve2. There are two curve() functions, one is in Curve1 and other in Curve2 classes. getSize() returns the value of iSize.
My base class header score.h looks like this:
#ifndef SCORE_H
#define SCORE_H
class Score
{
private:
int *ipScore;
float fAverage;
int iSize;
public:
Score(
void enterScores();
void calcAverage();
void output();
void output(float, int*);
void setSize();
int getSize();
void setScore();
int *getScore();
float getAverage();
};
#endif
You can see that I have used curve1Obj to enter scores, calculate average and output. So if I call getSize() function with cuve1Obj, it gives the right size that I took from user in enterScores() function. Also the result is same if I call getSize() in score.cpp definition file in any of the functions (obviously).
.....
The problem is when I call curve() function of Curve2 class in main (line 23) with the object curve2Obj, it creates a new set of ipScore, fAverage and iSize (i think?) with garbage values. So when I call getSize() in curve() definition in curve2.cpp, it outputs the garbage.
.....
How can I cause it to return the old values that are set in curve1.cpp?
Here is my curve2.cpp
#include <iostream>
#include "curve2.h"
using namespace std;
void Curve2::curve()
{
cout << "getSize() returns: " << getSize() << endl; // out comes the garbage
}
Can I use a function to simply put values from old to new variables? If yes then how?
Well, basically your problem can't be easily solved the way it is.
Like you said:
1 - Don't use constructors of any type.
2 - Don't use vectors.
3 - Using dynamic new and delete etc. etc.
Use the constructors or stick with what G. Samaras and Richard Hodges said. You can only solve this that way.
There is limited information available here but I would say that your Score constructor has not initialised ipScore or iSize.
If you are hell-bent on using a pointer to a dynamically allocated array of ints for your score then at least null out the pointer in the constructor and test for null in the average function (i.e. no scores yet).
Better yet... use a std::vector of int for your scores.
Why are people still using new and delete? What the hell are they teaching in schools?
What I think you want is this:
#include <vector>
class Score {
public:
Score()
: _scores()
, _average(0)
{ }
void calcAverage() {
double total = 0;
if(auto s = _scores.size() > 0) {
for (const auto& v : _scores)
total += v;
total /= s;
}
_average = total;
}
virtual void curve() = 0;
protected:
// one of the few correct uses of 'protected' - giving limited access to data as interface to derived classes
const std::vector<double>& scores() const {
return _scores;
}
// or
std::vector<double> copyScores() const {
return _scores;
}
private:
// use doubles since you'll be doing floating point arithmetic
std::vector<double> _scores;
double _average;
};
class Curve1 : public Score {
public:
virtual void curve() override {
// custom curve function here
// written in terms of scores() or copyScores() if you want to make changes to the array
}
};
class Curve2 : public Score {
public:
virtual void curve() override {
// custom curve function here
// written in terms of scores();
}
};
You need to understand inheritance. Curve1 inherits from Score. Curve2 inherits from Score.
Now see this example:
#include <iostream>
class Base {
int x;
};
class A : public Base {
int a;
public:
void set_a(int arg) {
a = arg;
}
int get_a() {
return a;
}
};
class B : public Base {
int b;
public:
void set_b(int arg) {
b = arg;
}
int get_b() {
return b;
}
};
int main() {
A a_object;
a_object.set_a(4);
B b_object;
b_object.set_b(a_object.get_a());
std::cout << "a of a_object = " << a_object.get_a() << "\n";
std::cout << "b of b_object = " << b_object.get_b() << "\n";
return 0;
}
class A, has as members x and a. Class B has as members x and b.
When I create an instance of class A, I will two data members created internally, x and a.
When I create an instance of class A, I will two data members created internally, x and b.
But, the first x and the second are DIFFERENT. They are a different cell in the memory!
something like this:
class Score {
public:
Score()
: _scores(0)
, _size(0)
, _average(0)
{ }
// copy constructor
Score(const Score& rhs)
: _scores( new double[rhs._size] )
, _size(rhs._size)
, _average(rhs._average)
{
if (_size) {
for(int i = 0 ; i < _size ; ++i) {
_scores[i] = rhs._scores[i];
}
}
}
// ... and if copy constructor then always a copy operator
Score& operator=(const Score& rhs) {
// assignment in terms of copy constructor - don't repeat yourself
Score tmp(rhs);
swap(tmp);
return *this;
}
// pre c++11 we make our own swap.
// post c++11 we would make non-throwing move constructor and move-assignment operator
void swap(Score& rhs) {
// std::swap is guaranteed not to throw
std::swap(_scores, rhs._scores);
std::swap(_size, rhs._size);
std::swap(_average, rhs._average);
}
~Score()
{
delete[] _scores;
}
void calcAverage() {
double total = 0;
if(_size > 0) {
for (int i = 0 ; i < _size ; ++i)
total += _scores[i];
total /= _size;
}
_average = total;
}
virtual void curve() {};
private:
// use doubles since you'll be doing floating point arithmetic
double * _scores;
int _size;
double _average;
};
// rmember to override the copy operators and assignment operators of derived classes
// remember to call the base class's operator