I am learning how to do OOP in c++. Please take a look at my simple example, and tell me if my OOP approach is incorrect.
I am looking to do this: create a "settings" type class that will be passed into a few other classes by reference. In the example this is the "ECU" class. I am using member initialization to pass the ECU class into each class. Is this the right way to do it?
Destructors in each class will delete any arrays created with the new command. In my code, the destructors for ECU are being called multiple times. If I had a "myArray" in ECU, and was using "delete[] myArray" in the ECU destructor, I would get errors. What's the right way to do this?
Also, the transmission and engine destructors are called before the program quits. Is this because the compiler knows they will not be used again?
// class_test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class ECU
{
public:
ECU()
{
cout << "ECU Constructor" << endl;
}
~ECU()
{
cout << "ECU Destructor" << endl;
}
void flash()
{
softwareVersion = 12;
}
int pullCode()
{
return softwareVersion;
}
private:
int softwareVersion;
};
class Engine
{
public:
Engine(ECU &e) : ecu(e)
{
horsepower = 76;
cout << "Engine Constructor" << endl;
}
~Engine()
{
cout << "Engine Destructor" << endl;
}
private:
ECU ecu;
int horsepower;
};
class Transmission
{
public:
Transmission(ECU &e) : ecu(e)
{
cout << "Transmission Constructor" << endl;
gearRatios = new double[6];
if (ecu.pullCode() == 12){
for (int i = 0; i < 6; i++)
gearRatios[i] = i+1.025;
cout << "gear ratios set to v12.0" << endl;
}
}
~Transmission()
{
delete[] gearRatios;
cout << "Transmission Destructor" << endl;
}
private:
ECU ecu;
double *gearRatios;
};
class Car
{
public:
Car(ECU &e) : ecu(e)
{
cout << "Car Constructor" << endl;
Engine myEngine(ecu);
Transmission myTrans(ecu);
}
~Car()
{
cout << "Car Destructor" << endl;
}
private:
ECU ecu;
};
int _tmain(int argc, _TCHAR* argv[])
{
ECU myComputer;
myComputer.flash();
Car myCar(myComputer);
system("pause");
return 0;
}
You're passing a reference, but you're not storing a reference:
ECU ecu;
means that your member will be a copy of the object that was referenced by the constructor's parameter.
If you want to store a reference, store a reference:
ECU& ecu;
Related
I have this code example and I want to understand why it behaves the way it does. This is a question from a past exam paper in an intro C++ course. I'm studying for the exam now and trying to solidify my understanding of class inheritance.
#include <iostream>
using namespace std;
class Bird {
public:
virtual void noise() { cout << "mumble" << endl; }
void move() { noise(); cout << "fly" << endl; }
};
class Canary: public Bird {
public:
void noise() { cout << "chirp" << endl; }
void move() { noise(); cout << "flap" << endl; }
};
class Tweety: public Canary {
public:
void noise() { cout << "tweet" << endl; }
void move() { noise(); cout << "run" << endl; }
};
int main() {
Canary *yellow = new Tweety();
yellow->noise();
yellow->move();
return 0;
}
I've run this code, and the output is:
tweet
tweet
flap
Which means it's calling the Tweety implementation of noise(), but it's calling the Canary implementation of move(). I'm confused about that. I understand the idea of polymorphism, and noise() is virtual, so it makes sense that it calls the Tweety version, since *yellow is a pointer to a Tweety. But why does it call the Canary version of move()?
I think what's confusing me, is the line:
Canary *yellow = new Tweety();
This says that *yellow is a Canary pointer, which points to a Tweety object. I'm sort of ok with that, because I get that pointers to base class can point to derived class. But *yellow points to a Tweety, so why doesn't it use Tweety's move()?
Thanks in advance for any help.
noise is virtual, so it is dynamically dispatched to the Tweety implementation when you call it.
move in not virtual, so the version to call is decided at compile time based on the type of you are dispatching the call through. Since yellow is a Canary the compiler does resolve what will be called at compile time and will explicitly call the move method in Canary.
The move() should also be virtual otherwise the version of the pointer type is called.
Sean and Alex are spot on.
Here are some more call cases that should help make sense of the different scenarios.
#include <iostream>
using namespace std;
class Bird {
public:
virtual void noise() { cout << "mumble" << endl; }
void move() { noise(); cout << "fly" << endl; }
void noise2() { cout << "mumble2" << endl; }
virtual void move2() { noise2(); cout << "fly2" << endl; }
};
class Canary: public Bird {
public:
void noise() { cout << "chirp" << endl; }
void move() { noise(); cout << "flap" << endl; }
void noise2() { cout << "chirp2" << endl; }
void move2() { noise2(); cout << "flap2" << endl; }
};
class Tweety: public Canary {
public:
void noise() { cout << "tweet" << endl; }
void move() { noise(); cout << "run" << endl; }
void noise2() { cout << "tweet2" << endl; }
void move2() { noise2(); cout << "run2" << endl; }
};
int main() {
Canary *yellow = new Tweety();
yellow->noise();
yellow->move();
yellow->noise2();
yellow->move2();
return 0;
}
/* OUTPUT:
tweet <- virtual dispatch
tweet <- virtual dispatch, via Bird::move()
flap <- direct call
chirp2 <- direct call
tweet2 <- direct call, from Tweety::move2()
run2 <- virtual dispatch
*/
So this is my code in Car.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
class Car
{
private:
int speed;
class GearBox;
GearBox& gearBox;
public:
Car();
~Car();
};
class Car::GearBox {
private:
int gear;
public:
GearBox();
~GearBox();
};
In Car.cpp i have
#include"Car.h"
Car::Car(): speed(0), gearBox(GearBox())
{
cout << "Car constructor" << endl;
}
Car::~Car()
{
cout << "Car destructor" << endl;
}
Car::GearBox::GearBox(): gear(0)
{
cout << "Gearbox constructor" << endl;
}
Car::GearBox::~GearBox()
{
cout << "GearBox destructor" << endl;
}
and my main is:
#include"Car.h"
int main() {
{
cout << "Starting program!" << endl;
Car car;
}
system("PAUSE");
return 0;
}
Result of the program is:
Starting program!
GearBox constructor
Car constructor
Car destructor
Why is Gearbox destructor not outputted?
(it makes sense to me that car has a reference to his gearbox because gearbox should exist while car does exist)
This would have to be a compiler bug, potentially related to the fact that it allows that reference initialisation in the first place (which is a Visual Studio extension, not compliant to any version of the actual, standardised, C++ language).
I believe I can reproduce this using an online VS compiler:
C++ compilers are allowed to elide copy operations even if they contain output like this, but not constructors and destructors.
Is GearBox instantiated?
Car::Car(): speed(0), gearBox(GearBox())
{
cout << "Car constructor" << endl;
}
↓
Car::Car(): speed(0)
{
static GearBox inst;
gearBox = inst;
cout << "Car constructor" << endl;
}
EDIT:
class Car
{
private:
int speed;
class GearBox { // referable
private:
int gear;
public:
GearBox() : gear(0) {
cout << "Gearbox constructor" << endl;
}
~GearBox() {
cout << "GearBox destructor" << endl;
}
};
GearBox* gearBox;
public:
Car();
~Car();
};
Car::Car(): speed(0)
{
static GearBox inst;
gearBox = &inst;
cout << "Car constructor" << endl;
}
I am learner in C++ and I am into the topic of constructors and destructors. I have compiled the code below and it returns the undefined reference to Book::~Book() error. But when I comment out the destructor, it is working fine. I think I can create member functions after using destructors. What am I doing wrong here? I have written my code below for better undertsanding
class Book
{
private:
int *pages;
int *price;
public:
Book() //default constructor
{
pages = new int;
price = new int;
*pages = 300;
*price = 8;
};
void pre_destructor()
{
std::cout << "The pages:" << *pages;
std::cout << "The price:" << *price;
}
~Book(); //destructor
void post_destructor()
{
std::cout << "The pages:" << *pages << "\n";
std::cout << "The price:" << *price << "\n";
delete pages;
delete price;
}
};
int main()
{
using namespace std;
Book book1;
cout << "Before using destructors" << endl;
cout << "---------------------------------"<< endl;
book1.pre_destructor();
cout << "After using destructors" << endl;
cout << "---------------------------------";
book1.post_destructor();
return 0;
} //destructor is called here
I've shortened that a little. the former void pre_destructor() was pointless; that's better placed in the dtor (short for "destructor") itself,
and the post_destructor() was even potentially harmful.
#include <iostream>
class Book
{
private:
int *pages;
int *price;
public:
Book() : pages(new int(300)), price(new int(8)) {}
~Book() {
std::cout << "The pages:" << *pages << "\n";
std::cout << "The price:" << *price << "\n";
delete price;
delete pages;
}
};
int main()
{
{
Book book1;
} //destructor is called here
return 0;
}
live at Coliru's
Your destructor is declared, but never defined.
Looks like "post_destructor" does the actual destruction. As a result, all you need to do is write you destructor as follows:
~Book() {} // empty, nothing to do here...
I want to know know how does g++ compiler knows which table to use if their are multiple vtable present in a base class. Like the following example.
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
class sample1
{
private:
int b;
public:
sample1():b(34)
{
cout << "In sample1 constructor" << endl;
}
virtual void print_b()
{
cout << this->b << endl;
}
void print_all()
{
this->print_b();
}
void sample_print_()
{
//cout << this->a << "String : " << this->str1 << endl;
cout << "hello" << endl;
this->print_all();
}
};
class sample2
{
private:
int b1;
public:
sample2():b1(34)
{
cout << "In sample1 constructor" << endl;
}
virtual void print_b1()
{
cout << this->b1 << endl;
}
void print_all1()
{
this->print_b1();
}
};
class sample : public sample1 , public sample2
{
private:
int a;
char *str1;
public:
sample():a(12),sample1()
{
strcpy(this->str1,"hello world");
cout << "In Constructor" << endl;
}
~sample()
{
free(this->str1);
cout << "In Destructor" << endl;
}
void sample_print()
{
//cout << this->a << "String : " << this->str1 << endl;
cout << "hello" << endl;
this->print_all();
}
virtual void print_a()
{
cout << this->a <<endl;
}
};
In above example, child class sample has two parent classes sample1 and sample2 and each of these class have vtable of their own. What if i call a virtual function from sample(child class)? How does the compiler know, in which class that virtual function is present so that it call use that particular vtable pointer ? I know their will be two vtable pointer present in sample(child class) class , so how does compiler know which one to use ?
//QuizShape.h
#ifndef QUIZSHAPE_H
#define QUIZHAPE_H
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class QuizShape
{
protected:
//outer and inner symbols, and label
char border, inner;
string quizLabel;
public:
//base class constructor with defaults
QuizShape(char out = '*', char in = '+', string name = "3x3 Square")
{
border = out;
inner = in;
quizLabel = name;
cout << "base class constructor, values set" << endl << endl;
};
//getters
char getBorder() const
{ return border; }
char getInner() const
{ return inner; }
string getQuizLabel() const
{ return quizLabel; }
//virtual functions to be defined later
virtual void draw( ) = 0;
virtual int getArea( ) = 0;
virtual int getPerimeter( ) = 0;
};
class Rectangle : public QuizShape
{
protected:
//height and with of a rectangle to be drawn
int height, width;
public:
//derived class constructor
Rectangle(char out, char in, string name,
int h = 3, int w = 3):QuizShape(out, in, name)
{
height = h;
width = w;
cout << "derived class constructor, values set" << endl << endl;
}
//getters
int getHeight() const
{ return height; }
int getWidth() const
{ return width; }
//*********************************************
virtual void draw(const Rectangle &rect1)
{
cout << "draw func" << endl;
cout << rect1.height << endl;
cout << rect1.getWidth() << endl;
cout << rect1.getQuizLabel() << endl;
}
virtual int getArea(const Rectangle &rect2)
{
cout << "area func" << endl;
cout << rect2.getInner() << endl;
cout << rect2.getBorder() << endl;
}
virtual int getPerimeter(const Rectangle &rect3)
{
cout << "perim func" << endl;
cout << rect3.height << endl;
cout << rect3.getWidth() << endl;
cout << rect3.getQuizLabel() << endl;
}
//************************************************
};
#endif
These are the class types so far.
//QuizShape.cpp
#include "QuizShape.h"
This currently does nothing but bridge the files.
//pass7.cpp
#include "QuizShape.cpp"
int main()
{
Rectangle r1('+', '-', "lol", 4, 5);
cout << r1.getHeight() << endl;
cout << r1.getWidth() << endl;
cout << r1.getInner() << endl;
cout << r1.getBorder() << endl;
cout << r1.getQuizLabel() << endl;
system("pause");
return 0;
}
The code will not compile due to the fact that Rectangle is supposedly an abstract class, and when hovering over the declaration of r1 in main, I receive the error
"Object of abstract class type "Rectangle" is not allowed".
I have checked other answers on this site and others and have not come across something that solves the problem.
NOTE: I understand that the statements for virtual functions ending in =0; cause the class to become an abstract one. QuizShape SHOULD be abstract. I have defined the virtual functions in Rectangle and yet it remains an abstract class.
How can I modify the virtual functions Rectangle class so that Rectangle is no longer abstract?
Your methods int the abstract class QuizShape are:
virtual void draw( ) = 0;
virtual int getArea( ) = 0;
virtual int getPerimeter( ) = 0;
but in Rectangle they take const Rectangle &rect1 as parameter so you shadowing the methods and not overriding the abstract one at all. You need to have methods in Rectangle with the same signature as the ones in the abstract base class.
The overridden methods must have the exact same signature, in the derived class you have given them arguments.