Multilevel inheritance/polymorphism and virtual function - c++

I have a multilevel inheritance (from Ship class -> MedicShip class -> Medic class) with virtual function code as below. I suppose the result should be :
Medic 10
Medic 10
But it generated strange result. On the other hand, if I only use one level inheritance (from Ship class -> Medic class without MedicShip class in between) the result will be OK. Could you find my mistake please? Many thank....
#ifndef FLEET_H
#define FLEET_H
#include <string>
#include <vector>
using namespace std;
class Ship
{
public:
Ship(){};
~Ship(){};
int weight;
string typeName;
int getWeight() const;
virtual string getTypeName() const = 0;
};
class MedicShip: public Ship
{
public:
MedicShip(){};
~MedicShip(){};
string getTypeName() const;
};
class Medic: public MedicShip
{
public:
Medic();
};
class Fleet
{
public:
Fleet(){};
vector<Ship*> ships;
vector<Ship*> shipList() const;
};
#endif // FLEET_H
#include "Fleet.h"
#include <iostream>
using namespace std;
vector<Ship*> Fleet::shipList() const
{
return ships;
}
int Ship::getWeight() const
{
return weight;
}
string Ship::getTypeName() const
{
return typeName;
}
string MedicShip::getTypeName() const
{
return typeName;
}
Medic::Medic()
{
weight = 10;
typeName = "Medic";
}
int main()
{
Fleet fleet;
MedicShip newMedic;
fleet.ships.push_back(&newMedic);
fleet.ships.push_back(&newMedic);
for (int j=0; j< fleet.shipList().size(); ++j)
{
Ship* s = fleet.shipList().at(j);
cout << s->getTypeName() << "\t" << s->getWeight() << endl;
}
cin.get();
return 0;
}

You haven't created any instances of class Medic. Did you mean to say
Medic newMedic;
instead of
MedicShip newMedic;
perhaps? So, the Medic constructor isn't being called and weight and typeName aren't being initialized.

~Ship(){};
The first mistake is right here. This destructor should be virtual if you want to delete derived class objects through base class pointer.

Related

C++: Passing a pointer of master to the worker

I am very new to pointers, so I have no idea what is going on with them.
I am trying to get a master class pass a pointer of itself to its worker/s, and I have no idea why it doesn't work.
#include <iostream>
#include <Windows.h>
using namespace std;
class BigOne {
public:
LittleOne workers[1] = {LittleOne(this)};
int increase = 0;
};
class LittleOne {
BigOne* master;
public:
LittleOne(BigOne*);
void Increment();
};
LittleOne::LittleOne(BigOne* upOne) {
master = upOne;
}
void LittleOne::Increment() {
master->increase++;
}
BigOne Outer;
int main() {
cout << Outer.increase << endl;
Outer.worker.Increment();
cout << Outer.increase << endl;
system("PAUSE");
}
This is my problem boiled down to its core components.
The problem isn't with pointers. It's mostly here:
class BigOne {
public:
LittleOne workers[1] = {LittleOne(this)};
int increase = 0;
};
When you define workers, what is LittleOne? How is it laid out in memory? How is it initialized? The compiler can't know, it hasn't seen the class definition yet. So you must flip the definitions around:
class BigOne;
class LittleOne {
BigOne* master;
public:
LittleOne(BigOne*);
void Increment();
};
class BigOne {
public:
LittleOne workers[1] = {LittleOne(this)};
int increase = 0;
};
The forward declaration allows us to define members that accept and return pointers. So the class LittleOne can have its definition written before BigOne. And now BigOne can define members of type LittleOne by value.
The issue is with forward declaration.
You can refer the following link for more details and explanation.
What are forward declarations in C++?

How to pass a private member variable to another class?

Based on my Snack.cpp, Snack header file, MiniVend header file & miniVend.cpp file, I am trying to move my Snack private member - price into my MiniVend.cpp file to generate the amount * price to return a total value of items in my machine. How do I access the price from another class?
Portion of my miniVend.cpp file
double miniVend::valueOfSnacks()
{
return //// I don't know how to get snacks price in here? I need to access snacks & getSnackPrice.
}
miniVend header
#ifndef MINIVEND
#define MINIVEND
#include <string>
#include "VendSlot.h"
#include "Snack.h"
using std::string;
class miniVend
{
public:
miniVend(VendSlot, VendSlot, VendSlot, VendSlot, double); //constructor
int numEmptySlots();
double valueOfSnacks();
//void buySnack(int);
double getMoney();
~miniVend(); //desructor
private:
VendSlot vendslot1; //declare all the vending slots.
VendSlot vendslot2; //declare all the vending slots.
VendSlot vendslot3; //declare all the vending slots.
VendSlot vendslot4; //declare all the vending slots.
double moneyInMachine; //money in the machine
};
#endif // !MINIVEND
Snack.cpp
#include "Snack.h"
#include <iostream>
#include <string>
using std::endl;
using std::string;
using std::cout;
using std::cin;
Snack::Snack() //default constructor
{
nameOfSnack = "bottled water";
snackPrice = 1.75;
numOfCalories = 0;
}
Snack::Snack(string name, double price, int cals)
{
nameOfSnack = name;
snackPrice = price;
numOfCalories = cals;
}
Snack::~Snack()
{
}
string Snack::getNameOfSnack()
{
return nameOfSnack;
}
double Snack::getSnackPrice()
{
return snackPrice;
}
int Snack::getNumOfCalories()
{
return numOfCalories;
}
Snack.h file
#ifndef SNACK_CPP
#define SNACK_CPP
#include <string>
using std::string;
class Snack
{
private:
string nameOfSnack;
double snackPrice;
int numOfCalories;
public:
Snack(); //default constructor
Snack(string name, double price, int cals); //overload constructor
~Snack(); //destructor
//Accessor functions
string getNameOfSnack(); //returns name of snack
double getSnackPrice(); //returns the price of the snack
int getNumOfCalories(); //returns number of calories of snack
};
#endif // !SNACK_CPP
Assuming getSnackPrice() is public, and Snack.h does exist, you should just be able to call
snackObject.getSnackPrice() * ammount
what you need is friend keyword. Define the
friend class className;
I don't really understand why you don't just implement get()? Accessing private data is really bad. You are breaking the encapsulation. But if you really want to know (i.e. you should NOT do it, it is really BAD), then you just return a reference to a private data as shown below
#include <iostream>
class A
{
public:
A(int a) : x(a) {}
int &getPrivateDataBAD() { return x; }
void print() { std::cout << x << std::endl; }
private:
int x;
};
class B
{
public:
void print(int &s) { std::cout << s << std::endl; }
};
int main()
{
A obj(2);
B bObj;
bObj.print( obj.getPrivateDataBAD() );
return 0;
}

Friend Function accessing private variables

I wrote a small piece of code to test friend functions. It worked fine for methods that didn't belong to a specific class but when I tried to put it into a class all it can access is the public variables (just as any object would).
#include <iostream>
#include <conio.h>
using namespace std;
class something{
int ip = 100;
public:
int x = 100;
void getIP();
friend void cIP::changeIP(something);
};
void something::getIP(){
cout << ip << endl;
}
class cIP{
public:
int i;
cIP();
cIP(int nIP);
something some;
void changeIP(something s);
};
cIP::cIP(){
i = 100;
}
cIP::cIP(int nIP){
i = nIP;
}
void cIP::changeIP(something s){
s.ip = i;
}
s.ip brings up the error member is inaccessible.

c++ getter not returning changed value outside class

I have 1 main class
class Vehicle{
private:
int fuel;
public:
int get_fuel(){ return this->fuel; }
void set_fuel(int fuel){ this->fuel = fuel; }
};
also 1 subclass of Vehicle
class Car : public Vehicle{
public:
Car();
};
Car::Car(){
set_fuel(500);
}
also my main.cpp file
#include <cstdlib>
#include <iostream>
#include "Vehicle.h"
#include "Car.h"
using namespace std;
int main(int argc, char *argcv[]){
Car c;
cout << c.get_fuel() << endl; //500
//set fuel to 200
c.set_fuel(200);
//print fuel again
cout << c.get_fuel() << endl;//still 500
}
why after using the setter the value still remains the same after i use the getter?
On VC++ 2012 your exact code works as expected. Output is 500 and 200.
class Vehicle {
private:
int _fuel;
public:
Vehicle(){
_fuel = 0;
}
int get_fuel(){
return _fuel;
}
// I like chainable setters, unless they need to signal errors :)
Vehicle& set_fuel(int fuel){
_fuel = fuel;
return *this;
}
};
class Car : public Vehicle {
public:
Car():Vehicle(){
set_fuel(500);
}
};
// using the code, in your main()
Car car;
std::cout << car.get_fuel() << std::endl; // 500
car.set_fuel(200);
std::cout << car.get_fuel() << std::endl; // actually 200
This is a slightly modified version. Place it in your .CPP file and try it. It can't not work!
PS: Stop using properties that have the same name as arguments. Always having to use this-> is very not cool! When you'll forget to use the this->, you'll see the bug of the century when you'll assign the value to itself and can't figure out what goes wrong.

Simple Polymorphism cast not working

I have a class SourceComponent, and its derived class, PeriodicSourceComponent.
Implementations are:
class SourceComponent : public Component
{
protected:
friend class UserInterface;
friend void readInput();
public:
virtual int returnType();
virtual int propagateLogic();
virtual void sourcePropagation(float);
virtual void accept(VisitorSources&);
SourceComponent();
};
and
#include "source_component.h"
class PeriodicSourceComponent : public SourceComponent
{
private:
int frequency;
friend void main();
friend void readInput();
friend class UserInterface;
public:
void sourcePropagation(float);
int returnType();
PeriodicSourceComponent();
};
When I try in some different class/method to do:
SourceComponent* s = new PeriodicSourceComponent;
it won't let me, sayin "a value of type periodicblabla cant be assigned to value of type sourceblabla". Why?
Edit:
Ok, in my main it looks lke this:
#include "source_component.h"
#include "periodic_source_component.h"
void main()
{
SourceComponent* s = new PeriodicSourceComponent;
}
And implementations of both classes:
source.cpp:
#include "source_component.h"
SourceComponent::SourceComponent()
{
outputState = -1;
}
int SourceComponent::propagateLogic()
{
return 1;
}
int SourceComponent::returnType()
{
return 5;
}
and periodic.cpp
#include "periodic_source_component.h"
PeriodicSourceComponent::PeriodicSourceComponent()
{
outputState = 0;
}
int PeriodicSourceComponent::returnType()
{
return 3;
}
void PeriodicSourceComponent::sourcePropagation(float time)
{
float t = time, period;
period = 1000000/frequency;
if(t > period)
{
while(t >= period)
t -= period;
}
if(t <= (period/2))
outputState = 0;
else
outputState = 1;
}
and its not working... (outputState is a member of class Component, base class of SourceComponent)
and the error message: A value of type "PeriodicSourceComponent*" cannot be assigned to a value of type "SourceComponent*".
Important Edit
When I try to compile, the actual compiler error is at PeriodicSourceComponent declaration, it says: "Base class undefined".
and also, I have two other derived classes from SourceComponent, but I don't see how they could interfere with this one..
EDIT 4
Ok so I figured out what causes the error, you were right of course, it something else I didn't post. I have class VisitorSources, heres definition:
#ifndef __VISITOR_SOURCES_H__
#define __VISITOR_SOURCES_H__
#include "component.h"
#include "impulse_source_component.h"
#include "arbitrary_source_component.h"
#include "periodic_source_component.h"
class VisitorSources
{
protected:
VisitorSources();
public:
virtual void visitImpulseSource(ImpulseSourceComponent*);
virtual void visitArbitrarySource(ArbitrarySourceComponent*);
virtual void visitPeriodicSource(PeriodicSourceComponent*);
void visitSource(int, float);
};
#endif
And its implementation is not yet written:
#include "visitor_sources.h"
void visitSource(int type, float time)
{
}
void VisitorSources::visitArbitrarySource(ArbitrarySourceComponent* a)
{
}
When I comment out the entire Visitor class and implementation, the above-mentioned errors are gone for some reason. I have no idea why...
The only error that remains is that when I try to use s->frequency, it says that frequency is not a member of SourceComponent, which is true, but it is a member of PeriodicSourceComponent, which is why I used the cast in the first place..
Finally, here's the Component class, the main class for all almost all other classes in the project :P
#ifndef __COMPONENT_H__
#define __COMPONENT_H__
#include <iostream>
#include <vector>
class Component
{
friend class UserInterface;
friend void readAndSimulate();
protected:
Component();
int numOfInputs;
int numOfOutputs;
std::vector<Component*> inputs;
std::vector<Component*> outputs;
friend void main();
float lengthOfSimulation;
int typeIfSource;
public:
int outputState;
virtual int propagateLogic() = 0;
virtual int returnType();
int beginPropagation();
virtual void sourcePropagation(float);
~Component();
};
#endif
And implementation:
#include "component.h"
#include <conio.h>
Component::Component()
{
}
int Component::beginPropagation()
{
std::vector<Component*>::const_iterator iter = outputs.begin();
for(;iter<outputs.end();++iter)
{
if ((*iter)->outputState == -2)
{
(*iter)->outputState = outputState;
return (*iter)->outputState;
}
}
std::vector<Component*>::const_iterator it = outputs.begin();
int finishedCycle, x;
while(1)
{
finishedCycle = 1;
for(; it < outputs.end(); ++it)
{
x = (*it)->propagateLogic();
if(!x)
finishedCycle = 0;
}
if(finishedCycle) break;
it = outputs.begin();
}
it = outputs.begin();
for(;it<outputs.end();++it)
(*it)->beginPropagation();
}
int Component::returnType()
{
return 0;
}
void Component::sourcePropagation(float)
{
}
Component::~Component()
{
std::vector<Component*>::const_iterator it = inputs.begin();
for(; it < inputs.end(); ++it)
{
if((*it) != NULL)
{
delete *it;
Component* p = *it;
p = NULL;
}
}
it = outputs.begin();
for(; it < inputs.end(); ++it)
{
if((*it) != NULL)
{
delete *it;
Component* p = *it;
p = NULL;
}
}
}
Are you using include guards in all your header files?
Not having them can cause the kinds of problems you're seeing.
Three guesses:
You copied and pasted code between header files and forgot to change the #include guards.
You use precompiled headers and included something before the #include "stdafx.h".
If you use precompiled headers, try deleting the .pch file.