I have a class:
Class Monster
{
private:
const int force;
const int prize;
const int damage;
}
In my code, I want to be able to easily create a unique Monster Object that I call Dragon which has default values for all the Monster's attributes that can't be initialized to different values (for example: all Dragons has force=5, prize=10, damage=10)
My question is- should Dragon be a subclass of Monster even though there is not realy a difference between the two except for the default values and the name of the object?
(In fact I have many types such as Dragon- each has it's own default values).
It seems that this is going to be a fine solution for my needs but I'm new to OOP and not sure it's acceptable or how to solve it differently, yet elegantly.
Although this might not be the cleanest solution, you could create an enum class for your different monster types and use a custom method to call the constructor.
enum class types {Dragon, Turtle, Squid};
class Monster {
private:
const int force;
const int prize;
const int damage;
public:
static Monster createMonster(types type) {
if (type == types::Dragon) {
return Monster(20, 10, 5);
}
else if (type == types::Squid) {
return Monster(5, 2, 3);
}
}
Monster(int f, int p, int d) : force(f), prize(p), damage(d){};
};
int main(void) {
Monster dragon1 = Monster::createMonster(types::Dragon);
Monster squid1 = Monster::createMonster(types::Squid);
return 0;
}
I am trying to get stockname to my derived class using a return function, but it shows a error 'argument of type is incompatible with parameter of type'.
strcpy(name,s.name()); //Problem
I tried to make it a constant char but that made a couple of errors.
I am making a project on stock market, text me your ideas.
#include<iostream>
#include<conio.h>
#include<fstream>
#include<string.h>
using namespace std;
class stock
{
char stockname[20];
float istockprice;
float fstockprice;
int demand;
public:
void senter();
void sdisplay();
int demands()
{
return demand;
}
char name()
{
return s.stockname[20];
}
};
class market : public stock
{
char stocksell[20];
char stockbuy[20];
float sellprice;
float rate;
public:
void marketdata();
void rate();
void search();
};
class transaction
{
public:
void credit();
void debit();
void transfer();
};
market m;
transaction t;
stock s;
void market::rate()
{
m.rate = demands();
m.rate += 1;
}
void market::search()
{
char name[30];
strcpy(name,s.name()); //Problem
ifstream search("Marketdata.txt");
if (!search)
{
cout << "Marketdata.txt file error";
return;
}
//while (search.read((char*)& m, sizeof(m)))
//{
// if (strcmp(m.stocksell,name)==0)
//{
//}
// }
}
You're confused about C style strings (and arrays). In C++ you should really use C++ style strings, but you've started this code with C strings so we'll carry on with that for now.
In C a string is an array of characters, to manipulate the string you need a pointer to the first element of the array. So this code is wrong
char name()
{
return s.stockname[20];
}
Firstly there's a total spurious s in there, I don't know what you think that does (and I'm surprised it compiles). But the main point is that because this is a C style string, the function should return a pointer.
char* name() // returns a pointer
{
return stockname;
}
So stockname is an array containing a C style string, and name is a method which returns a pointer to the first element of the array.
Weird as it is, that how you do strings in C. C++ strings are so much easier, in many different ways. If you really want to learn C++, you should leave all the legacy C stuff behind.
I'm a student learning c++.
I have two objects ("City" and "Parser") and I'd like one object("Parser") to modify to other one("City").
The only "problem" is that I have to send the object("City") in the other one's constructor (The code is showing what I mean).
class City {
public:
City()
: peopleCount { 0 }
{};
int peopleCount;
};
class Parser {
public:
Parser(const char *filename, City &c)
: _filename { filename },
_c { c }
{};
void fillCity() { _c.peopleCount = 3; };
const char *_filename;
City _c;
};
int main(int argc, char *argv[])
{
City c;
Parser p(argv[1], c);
p.fillCity();
std::cout << c.peopleCount << std::endl; // I would like my output to be "3"
return 0;
}
I could do that in C by sending a raw pointer in the constructor.
But since I discover this langage, everyone is saying that raw pointer must be avoided.
I checked smart pointers but they would "delete" my variable (my variable is from the Stack, for that reason I don't want to delete it).
I do not want to copy the "City" in the "Parser" (because copying objects can be avoided ?).
I am aware that I could send a reference of a City object to the member function "fillCity" but I would like to know if the one object can hold another object without copying it.
Is there another way to do that without using raw pointer ?
Thanks in advance.
If you want to share objects while having the life time of these objects under control, you can use shared_ptr. Thereby, the shared object will be destructed once all references to it have been released (i.e. the last shared_ptr-wrapper got destructed):
class City {
public:
City()
: peopleCount(0)
{};
int peopleCount;
};
class Parser {
public:
Parser(const char *filename, std::shared_ptr<City> c)
: _filename (filename),
_c (c) {};
void fillCity() { _c->peopleCount = 3; };
const char *_filename;
std::shared_ptr<City> _c;
};
int main(int argc, char *argv[])
{
std::shared_ptr<City> c = std::make_shared<City>();
Parser p("somefilename", c);
p.fillCity();
std::cout << c->peopleCount << std::endl;
return 0;
}
In the Parser constructor, you pass the City argument by reference. But then you copy the object to store it in _c.
You should make _c a reference as well.
Another option (after Some Programmer Dude's correct answer) is to pass c in as a reference to some of P's member functions, e.g.:
class Parser {
public:
Parser(const char *filename)
: _filename { filename }
{};
void fillCity(City &c) { c.peopleCount = 3; };
const char *_filename;
};
Used like:
int main(int argc, char *argv[])
{
City c;
Parser p(argv[1]);
p.fillCity(c);
std::cout << c.peopleCount << std::endl; // I would like my output to be "3"
return 0;
}
This may or may not be how you want it - but if you just have one or a small number of functions this is quite convinient.
On another point - I would not say passing-by-pointer is so bad, for example you can at least default construct with a pointer (default value being nullptr) and then later pass in the C object. The only "issue" is that you need to be careful that C exists for the lifetime of P or that you tell P if/when C dissapears... not really rocket sceince :) and it can be quite convinient.
Let's say I have the following:
char cipan[9];
then what should I pass to the function? how about the get and set method??
I'm currently doing like this
set method
void setCipan(char cipan[]){
this->cipan = cipan;
}
and the get method
char getCipan(){
return cipan;
}
and I get an error when compiling??
Im totally blur.. can someone explain what should i pass to the function??
class userData{
private:
string name;
char dateCreate[9];
void userDataInput(string name,char dateCreate[]){
this->name = name;
this->dateCreate = dateCreate;
}
public:
//constructor
userData(string name){
userDataInput(name,dateCreate);
}
userData(string name,char dateCreate[]){
userDataInput(name,dateCreate);
}
//mutator methods
void changeName(string name){this->name = name;}
void changeDateCreate(char *dateCreate){this->dateCreate = dateCreate;}
//accesor methods
string getName(){return name;}
char *getDateCreate(){return dateCreate;}
};
I'd do the following:
void setCipan(const char* new_cipan)
{
strcpy(cipan, new_cipan);
}
const char* getCipan() const
{
return cipan;
}
Of course, the better approach is to use std::string:
void setCipan(const string& new_cipan)
{
cipan = new_cipan;
}
string getCipan() const
{
return cipan;
}
Constructor's purpose is to initialize class variables. I think it's unnecessary to call another method in the constructor to do initialization.
void userDataInput(string name,char dateCreate[]){
this->name = name;
this->dateCreate = dateCreate; // Both the dateCreate are class variables.
}
userData(string name){
userDataInput(name,dateCreate); // dateCreate is already a class variable.
}
dateCreate is the class scope variable. You are just passing it to a method, and re-assigning the same to dateCreate. Assignment operation doesn't copy elements of one array to another and are invalid operations.
To copy array elements, use std::copy instead.
I want to create an immutable data structure which, say, can be initialized from a file.
class Image {
public:
const int width,height;
Image(const char *filename) {
MetaData md((readDataFromFile(filename)));
width = md.width(); // Error! width is const
height = md.height(); // Error! height is const
}
};
What I could do to fix the problem is
class Image {
MetaData md;
public:
const int width,height;
Image(const char *filename):
md(readDataFromFile(filename)),
width(md.width()),height(md.height()) {}
};
However
It forces me to save MetaData as a field in my object. Which I don't always want.
Sometimes the logic in the constructor is much more complex than a single read (say, error handling can take a few lines)
So the only solution I thought of is along the lines of
class A {
int stub;
int init(){/* constructor logic goes here */}
A():stub(init)/*now initialize all the const fields you wish
after the constructor ran */{}
};
Is there a better idea? (In Java, you're allowed initializing finals in the constructor).
You could move width and height into one type and move the initialization code into an initialization helper function:
// header:
struct Size {
int width, height;
Size(int w, int h) : width(w), height(h) {}
};
class Image {
const Size size; // public data members are usually discouraged
public:
Image(const char *filename);
};
// implementation:
namespace {
Size init_helper(const char* filename) {
MetaData md((readDataFromFile(filename)));
return Size(md.width(), md.height());
}
}
Image::Image(const char* filename) : size(init_helper(filename)) {}
You can simply use the NamedConstructor idiom here:
class Image
{
public:
static Image FromFile(char const* fileName)
{
MetaData md(filename);
return Image(md.height(), md.width());
}
private:
Image(int h, int w): mHeight(h), mWidth(w) {}
int const mHeight, mWidth;
};
One of the main advantage of Named Constructors is their obviousness: the name indicates you are building your object from a file. Of course it's slightly more verbose:
Image i = Image::FromFile("foo.png");
But that never troubled me.
If it was C++0x, I would recommend this (delegating constructors):
class Image
{
public:
const int width, height;
Image(const char* filename) : Image(readDataFromFile(filename)) { }
Image(const MetaData& md) : width(md.width()), height(md.height()) { }
};
You should add inline getters for the width and height instead of public const member variables. The compiler will make this solution as fast as the original try.
class Image {
public:
Image(const char *filename){ // No change here
MetaData md((readDataFromFile(filename)));
width = md.width();
height = md.height();
}
int GetWidth() const { return width; }
int GetHeight() const { return height; }
private:
int width,height;
};
P.S.: I used to write private things at the end because they are less important for the user of the class.
First, you should understand the constructor body is just for running code to complete initializing your object as a whole; the members must be completely initialized before the body is entered.
Ergo, all members are initialized in an (implicit unless made explicit) initialization list. Clearly, const variables must be initialized in the list because once you enter the body, they are already suppose to be initialized; you'd simply be trying to assign them.
Generally, you don't have const members. If you want those members to be immutable, just don't give any public access to them that could change them. (Also, having const members make your class non-assignable; typically unnecessarily.) Going this route easily fixes your problem, as you'd just assign them values in the body of the constructor like you wish.
A method to do what you want while maintaining const could be:
class ImageBase
{
public:
const int width, height;
protected:
ImageBase(const MetaData& md) :
width(md.width()),
height(md.height())
{}
// not meant to be public to users of Image
~ImageBase(void) {}
};
class Image : public ImageBase
{
public:
Image(const char* filename) : // v temporary!
ImageBase(MetaData(readDataFromFile(filename)))
{}
};
I don't think this route is worth it.
You could cast away the constness in the constructor:
class Image {
public:
const int width,height;
Image(const char *filename) : width(0), height(0) {
MetaData md(readDataFromFile(filename));
int* widthModifier = const_cast<int*>(&width);
int* heightModifier = const_cast<int*>(&height);
cout << "Initial width " << width << "\n";
cout << "Initial height " << height << "\n";
*widthModifier = md.GetWidth();
*heightModifier = md.GetHeight();
cout << "After const to the cleaners " << width << "\n";
cout << "After const to the cleaners " << height << "\n";
}
};
That would achieve what you want to do but I must say I personally would stay away from that because it causes undefined behavior according to the standard (excerpt from cppreference)
const_cast makes it possible to form a reference or pointer to
non-const type that is actually referring to a const object ...
Modifying a const object through a non-const
access path ... results in undefined behavior.
I would fear any public data members(at least in regarding your particular example). I would go with Georg's approach or make the data private and provide only the getter.
How about passing MetaData as an argument to the constructor. This gives a lot of benefits:
a) The constructor interface makes it clear about the dependency on MetaData.
b) It facilitates testing of the Image class with different types of MetaData (subclasses)
So, I would probably suggest similar to follows:
struct MD{
int f(){return 0;}
};
struct A{
A(MD &r) : m(r.f()){}
int const m;
};
int main(){}
I'd use a static method:
class Image {
public:
static Image* createFromFile( const std::string& filename ) {
//read height, width...
return new Image( width, height );
}
//ctor etc...
}
class A
{
public:
int weight,height;
public:
A():weight(0),height(0)
{
}
A(const int& weight1,const int& height1):weight(weight1),height(height1)
{
cout<<"Inside"<<"\n";
}
};
static A obj_1;
class Test
{
const int height,weight;
public:
Test(A& obj = obj_1):height(obj.height),weight(obj.weight)
{
}
int getWeight()
{
return weight;
}
int getHeight()
{
return height;
}
};
int main()
{
Test obj;
cout<<obj.getWeight()<<"\n";
cout<<obj.getHeight()<<"\n";
A obj1(1,2);
Test obj2(obj1);
cout<<obj2.getWeight()<<"\n";
cout<<obj2.getHeight()<<"\n";
return 0;
}
As far my understanding i think this mechanism will work.
This is one of my least favorite aspects of C++ when compared to Java. I'll use an example I was working on when I needed to solve this problem.
What follows is the equivalent of a readObject method. It deserializes a Video key from a provided file path.
#include <fstream>
#include <sstream>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
using namespace std;
using namespace boost::filesystem;
using namespace boost::archive;
class VideoKey
{
private:
const string source;
const double fps;
const double keyFPS;
const int numFrames;
const int width;
const int height;
const size_t numKeyFrames;
//Add a private constructor that takes in all the fields
VideoKey(const string& source,
const double fps,
const double keyFPS,
const int numFrames,
const int width,
const int height,
const size_t numKeyFrames)
//Use an initializer list here
: source(source), fps(fps), keyFPS(keyFPS), numFrames(numFrames), width(width), height(height), numKeyFrames(numKeyFrames)
{
//Nothing inside this constructor
}
public:
//Then create a public static initializer method that takes in
//the source from which all the fields are derived
//It will extract all the fields and feed them to the private constructor
//It will then return the constructed object
//None of your fields are exposed and they are all const.
const static VideoKey create(const path& signaturePath)
{
const path keyPath = getKeyPath(signaturePath);
ifstream inputStream;
inputStream.open(keyPath.c_str(), ios::binary | ios::in);
if (!inputStream.is_open())
{
stringstream errorStream;
errorStream << "Unable to open video key for reading: " << keyPath;
throw exception(errorStream.str().c_str());
}
string source;
double fps;
double keyFPS;
int numFrames;
int width;
int height;
size_t numKeyFrames;
{
binary_iarchive inputArchive(inputStream);
inputArchive & source;
inputArchive & fps;
inputArchive & keyFPS;
inputArchive & numFrames;
inputArchive & width;
inputArchive & height;
inputArchive & numKeyFrames;
}
inputStream.close();
//Finally, call your private constructor and return
return VideoKey(source, fps, keyFPS, numFrames, width, height, numKeyFrames);
}