Hi everyone,
Just studying a bit of c++11. I’m trying to transfer the ownership of an object(Vehicle) from one vector to another one. Not sure if that makes much sense. I would like the object not to be created and destroyed, just moved.
Any other recommendations or criticisms (about the class structure, types used…) are very welcome.
This is just for the sake of study, the more I learn the better.
I’m trying to transfer ownership on buyAnyAvailableVehicle()
(end of the file). Current code does not compile but using copies works fine.
Its a bit messy. I can isolate the move code if needed.
Thanks for reading!
in ofApp.h
#pragma once
#include "ofMain.h"
//------------------
enum VehicleType {
car_type,
bycicle_type,
tricicle_type,
unknown_type
};
//------------------
const static string toString(const VehicleType & type) {
switch (type) {
case car_type:
return "car";
case bycicle_type:
return "bycicle";
case tricicle_type:
return "tricicle";
case unknown_type:
return "unknown";
default:
return "Undefined";
}
}
//------------------
enum WheelPosition {
front_pos,
rear_pos,
right_pos,
left_pos,
frontRight_pos,
frontLeft_pos,
rearRight_pos,
rearLeft_pos
};
typedef std::set<WheelPosition> WheelPositionSet;
//------------------
const static string toString(const WheelPosition & position) {
switch (position) {
case front_pos:
return "front";
case rear_pos:
return "rear";
case right_pos:
return "right";
case left_pos:
return "left";
case frontRight_pos:
return "frontRight";
case frontLeft_pos:
return "frontLeft";
case rearRight_pos:
return "rearRight";
case rearLeft_pos:
return "rearLeft";
default:
return "Undefined";
}
}
//------------------
class Uncopyable {
protected: // allow construction
Uncopyable() {} // and destruction of
~Uncopyable() {} // derived objects...
private:
Uncopyable(const Uncopyable&); // ...but prevent copying
Uncopyable& operator= (const Uncopyable&);
};
//------------------
// let-s try make wheels uncopyable
class Wheel{// : private Uncopyable {
public:
Wheel(int radius = 32) : radius(radius) {}
int getRadius() { return this->radius; }
private:
int radius;
};
// a vector<Wheel> will create copies.
// let's use a vector of pointers to wheels.
// they are unique_pointers coz only a vehicle will own them.
typedef vector<unique_ptr<Wheel>> Wheels;
//------------------
class VehicleSpecs {
public:
VehicleSpecs(const VehicleType & type) : type(type) {};
// VehicleSpecs(const Wheels & other) : wheels(other) {};
const VehicleType & getType() const { return this->type; }
const WheelPositionSet & getWheelPositionSet() const { return this->wheelspecs; }
void setType(VehicleType type) { this->type = type; }
void addWheel(WheelPosition position) { this->wheelspecs.insert(position); }
void removeWheel(WheelPosition position) { this->wheelspecs.erase(position); }
private:
const VehicleSpecs(); // should we allow a default constructor? empty specs?
WheelPositionSet wheelspecs;
VehicleType type;
};
//------------------
// Abstract Base class (virtual funtions + some functions defined)
// not an Interface class, (only pure virtual funtions allowed)
class Vehicle : public ofNode{//, private Uncopyable{
public:
// move constructor
// this is important, since wheels cant be copied we need to move them
// otherwise whats the point of a move operator..
Vehicle(Vehicle && other)
: specs(std::move(other.specs)),
wheels(std::move(other.wheels))
{
std::cout << "move "<< std::endl;
}
// Base classes must have virtual destructor
virtual ~Vehicle() {
// std::cout << "destructor " << std::endl;
}
const VehicleType & getVehicleType() const { return this->specs.getType(); }
Wheels & accessWheelSet() { return this->wheels; }
VehicleSpecs & getSpecs() { return this->specs; }
void printType() {
cout << "This vehicle is a ";
cout << toString(this->getSpecs().getType()) << endl;
}
void printInstalledWheels() {
for (auto & wheelPos : this->getSpecs().getWheelPositionSet()) {
cout << "This vehicle has a ";
cout << toString(wheelPos);
cout << " wheel" << endl;
}
}
protected: // no one must implement vehicle, only inheritance allowed
Vehicle(const VehicleType & type) : specs(type) {}
// Vehicle(const VehicleSpecs & incoming): specs(incoming) {}
const VehicleSpecs & getSpecs() const { return this->specs; } // getSpecs has to be available for all vehicles.
virtual void moveForward() = 0 { // The = 0 means this function is pure virtual
this->move(1, 0, 0);
};
virtual void turnRight() = 0 {
this->rollDeg(1);
};
virtual void turnLeft() = 0 {
this->rollDeg(-1);
};
VehicleSpecs specs;
Wheels wheels;
};
typedef shared_ptr<Vehicle> VehiclePtr;
//------------------
// this object will (or will not) have a threaded function, depending on specs.
// engine thread might run out of sync with GL thread.
class Car : public Vehicle {
public:
Car() : Vehicle(car_type) {};
// void startEngine();
// void stopEngine();
void moveForward() override { // override
this->move(1, 0, 0); // do something
};
void turnRight() override {
this->rollDeg(1);
};
void turnLeft() override {
this->rollDeg(-1);
};
};
typedef shared_ptr<Car> CarPtr;
//------------------
class Bicycle : public Vehicle {
public:
Bicycle() : Vehicle(bycicle_type) {};
void moveForward() override { // override
this->move(1, 0, 0); // do something
};
void turnRight() override {
this->rollDeg(1);
};
void turnLeft() override {
this->rollDeg(-1);
};
};
//------------------
class Tricicle : public Vehicle {
public:
Tricicle() : Vehicle(tricicle_type) {};
void moveForward() override { // override
this->move(1, 0, 0); // do something
};
void turnRight() override {
this->rollDeg(1);
};
void turnLeft() override {
this->rollDeg(-1);
};
};
//------------------
// why cant this be inside vehicle class??
static VehicleType getType(VehiclePtr vehicle) {
if (dynamic_pointer_cast<Car>(vehicle)) {
return car_type;
}
else if (dynamic_pointer_cast<Bicycle>(vehicle)) {
return bycicle_type;
}
else if (dynamic_pointer_cast<Tricicle>(vehicle)) {
return tricicle_type;
}
else {
return unknown_type;
}
}
//------------------
// a Factory Class
class Manufacturer {
public:
const VehiclePtr makeVehicle(VehicleType type) {
switch (type) {
case car_type:
VehiclesToSell.emplace_back(new Car);
break;
case bycicle_type:
VehiclesToSell.emplace_back(new Bicycle);
break;
case tricicle_type:
VehiclesToSell.emplace_back(new Tricicle);
break;
default:
cout << "error!";
}
VehiclePtr currentVehicle = VehiclesToSell.back();
installWeelset(*currentVehicle);
return currentVehicle;
}
void installWeel(Vehicle& vehicle, WheelPosition position) {
vehicle.getSpecs().addWheel(position);
vehicle.accessWheelSet().emplace_back(new Wheel);
}
void installWeelset(Vehicle& vehicle) {
switch (vehicle.getVehicleType()) {
case car_type:
installWeel(vehicle, frontRight_pos);
installWeel(vehicle, frontLeft_pos);
installWeel(vehicle, rearRight_pos);
installWeel(vehicle, rearLeft_pos);
break;
case bycicle_type:
installWeel(vehicle, front_pos);
installWeel(vehicle, rear_pos);
break;
case tricicle_type:
installWeel(vehicle, front_pos);
installWeel(vehicle, rearRight_pos);
installWeel(vehicle, rearLeft_pos);
break;
default:
cout << "error!";
}
}
Vehicle && sellSomeVehicle() {
return std::move(*this->VehiclesToSell.back());
}
void printAmountOfVechiclesInStock() {
cout << VehiclesToSell.size() << endl;
}
private:
vector<VehiclePtr> VehiclesToSell;
};
class User {
public:
void buyAnyAvailableVehicle(Manufacturer& manufacturer) {
vehicles.emplace_back(manufacturer.sellSomeVehicle());
}
void printAmountOfVechiclesOwned() {
cout << vehicles.size() << endl;
}
private:
vector<VehiclePtr> vehicles;
};
class ofApp : public ofBaseApp {
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y);
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
Manufacturer manufacturer;
User user;
};
in ofApp.cpp
void ofApp::setup(){
VehiclePtr aVehicle;
aVehicle = manufacturer.makeVehicle(car_type);
aVehicle.get()->printType();
aVehicle.get()->printInstalledWheels();
manufacturer.printAmountOfVechiclesInStock();
user.buyAnyAvailableVehicle(manufacturer);
manufacturer.printAmountOfVechiclesInStock();
user.printAmountOfVechiclesOwned();
}