I have a class A which handles file by opening, reading and closing. I also have another class B that use A to read file. B has instance of A as private member data. I want to reuse the a and use it to read multiple files using this instance. I also read some where that we cannot copy any of the stream. So my question is how can I handle class A to read multiple files in B?
class A{
A(std::string s){
f.open(s);
}
void read_file(){
/// read file
// close after reading
f.close();
}
private:
std::ifstream f;
};
class B{
B(std::string s_):a(s_){}
void read_multiple_files(){
a.read_file();
// now lets read another file
a = A("another_file_1.txt");
a.read_file();
////////////////////
// now lets read another file
a = A("another_file_2.txt");
a.read_file();
}
private:
A a
};
This is probably a design issue. There seems no reason for B to hold an instance of A unless it needs to keep a file handle across different method calls.
Instead, simply create an A to read each file:
class B {
void read_multiple_files() {
// read our files
auto result = A("another_file_1.txt").read_file();
auto result_2 = A("another_file_2.txt").read_file();
...
}
}
Related
I'm facing a problem, a design problem. There is this template class which represent File handling/driver interface. Here is the barebone of that class.
---------------------------- FileDriver.h---------------------------
namespace DatabaseManager {
template<class T>
class FileDriver {
FileDriver(const char *file_name) : file_name(file_name) {}
public :
T* fetch(size_t rec_size, long rec_num, long offset , bool write_enabled) {
// fetch data from file
}
int insert(T *rec, size_t rec_size, long rec_num, long offset) {
// insert data into file
}
inline int release(T *rec, size_t rec_size, int rec_num) {
// close the file
}
};
}
Now this class is used by any class in the system which needs I/O operation. But as its a template class so i have to create objects of this class everytime i need to access a file. For example here is how a function uses this class.
---------------------- ParseSparseParticles.cpp ------------------
#include "FileDriver.h"
bool ParseSparseParticles::openFile() throw(ParseSparseParticlesException)
{
// DatabaseManager::FileMetaInfo is a struct containing meta information about a file
DatabaseManager::FileMetaInfo *meta_info = nullptr;
DatabaseManager::SparseParticles *particle_data = nullptr;
DatabaseManager::FileDriver<DatabaseManager::FileMetaInfo> meta_hndlr(meta_file_name.str().c_str());
meta_info = meta_hndlr.fetch(sizeof(DatabaseManager::FileMetaInfo), 1, static_cast<int>(DatabaseManager::file_map_pos::START), false);
if (meta_info) {
DatabaseManager::FileDriver<DatabaseManager::SparseParticles> data_hndlr(file_name.str().c_str());
particle_data = data_hndlr.fetch(sizeof(DatabaseManager::SparseParticles),
meta_info->num_rec, static_cast<int>(DatabaseManager::file_map_pos::START), false);
if (particle_data) {
data_hndlr.release(particle_data, sizeof(DatabaseManager::SparseParticles), meta_info->num_rec);
meta_hndlr.release(meta_info, sizeof(DatabaseManager::FileMetaInfo), 1);
return true;
} else {
throw ParseSparseParticlesException("Cannot open Sparse Particles File");
}
} else {
throw ParseSparseParticlesException("Cannot open Meta Info File");
}
}
So i have to like follow this exact same steps everytime i need to access any file.
1. Open the meta info file
2. Open the actual data file
3. Close the data file
4. Close the meta file
And this gets tiresome after sometime, worse it leads to duplicate code, unstructured code, as file operation is done all over the system. So i was thinking about making an interface that will abstract the operation of I/O. And in the process of doing so i stumbled when i wanted to create FileDriver member object of the interface class, like so
--------------------------- IOInterface.h ---------------------------
#include "FileDriver.h"
template<typename MetaFileType, typename FileType>
class IOInterface {
DatabaseManager::FileDriver<MetaFileType> meta_orb; // won't compile
DatabaseManager::FileDriver<FileType> data_orb; // won't compile
};
But this won't compile as i'm including a template header into another template header. So can please anyone tell me how to solve this problem. How can i make an class that will act like an interface to FileDriver that will store the FileDriver object as long as that class object is alive.
Thanks
UPDATE
The error i'm getting while compiling is with the IOInterface constructor.
IOInterface::IOInterface(std::string data_dir, std::string file_prefix, int id) :
data_dir(data_dir),
file_prefix(file_prefix),
file_id(id)
{}
/var/local/PolymerizationSimulation/include/IOInterface.h:7: error: no matching function for call to 'DatabaseManager::FileDriver<DatabaseManager::MetaFileType>::FileDriver()'
/var/local/PolymerizationSimulation/include/IOInterface.h:7: error: no matching function for call to 'DatabaseManager::FileDriver<DatabaseManager::FileType>::FileDriver()'
Some hints from looking at your code:
You miss semicolons after class definition:
};
^
also from your example, FileDriver is not inside DatabaseManager
In this class:
template<class T>
class FileDriver {
all members are private, even constructor, so you cannot access it. Finally this class does not provide default constructor needed by:
DatabaseManager::FileDriver<MetaFileType> meta_orb; // won't compile
DatabaseManager::FileDriver<FileType> data_orb; // won't compile
so compiler have no idea how to create those instances, add it for FileDriver:
FileDriver(){}
I have a class A which has a function called openFile(const char * name), which opens a file.
I have two child classes Reader and Writer
Reader opens the file in a reading mode.
Writer opens the file in a writing mode.
I'm using fopen to open the file.
I would like to open this file in either a reading mode or a writing mode, depending on which child class is calling this method.
Is it possible to do this without sending any extra parameters to the parent class?
Of course, something like this is exactly what inheritance is meant to do:
class A {
public:
virtual void openFile(const char* name) = 0;
// If A cannot open a file on its own, else implement it
// rest of implementation
};
class Reader : public A {
public:
virtual void openFile(const char* name) {//open file in read mode}
//rest of implemenation
};
and handle Write analog. Then, given a pointer or reference of type A* or A& pointing or referring to one of the children, the right function will be chosen:
A* a1 = new Reader{};
A* a2 = new Writer{};
a1->openFile("test.in"); // calls Reader.openFile()
a2->openFile("test.out"); // calls Writer.openFile()
How would i extend the FILE class to use its methods? In other words, how can i use all of the functions that are provided with the default FILE object and still have the same functionality that mimics the actual functions?
class myFile
{
File *_f;
public:
myFile(File *f){ /*open the file here, then make _f=f;*/ };
virtual ~myFile(){ /*close the file here*/ };
// and can add more methods here
}
class MyClass
{
private:
AnotherClass obj;
float d;
int k;
public:
MyClass(float d = 0.3, int k = 10);
virtual ~MyClass();
// other methods goes here
}
Is it possible to have a method that allow this class (MyClass) to save to its attribute values on the disk (hard drive) void storeOnDisk(string path){...} and another method which allow to load the attribute values from disk void loadFromDisk(string path) ?
If it is possible, should I also call loadFromDisk(path) in the constructor of MyClass (create another constructor maybe), and storeOnDisk(path) in the destructor of MyClass so that all current values can be saved when quitting the program that instanciated MyClass ?
It depends on what exactly you want to achieve. However, usually, you'd not like to have such things in ctor/dtor since in C++ "copies" and "temporary objects" show up sometimes. Ctors/dtors are called when they are created/removed, just like regular objects, and it would also touch the files unless you prepare the code really well.
Often it is somewhat easier to keep a separate class that handles the reading/writing. Imagine a MyClassStorage class that would be a friend of the MyClass and that would contain only two methods: MyClass read(path) and write(path MyClass&).
If you like having it in single class or if you don't want to do everything manually, you can look at some serialization frameworks like Boost::Serialization. There are many short and easy examples on how to handle it, but - still - you'll have to read a bit about it first.
EDIT:
See http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/tutorial.html and the "A very simple case" section. It shows how to read/write a gps_position class. Note that this class iteself is very simple except that it contains an additional serialize function. This function works 'automagically' both as reader and writer. Since usually you want to read the same fields as you wanted to write, there's not need to say it twice (instead of saying read-A-B-C and write-A-B-C you say: handleThemForMe-A-B-C).
Then, in main you have example of usage. The text_oarchive and text_iarchive act as output and input files. Some gps_position object is created and named g, then saved to a file called filename, and then it is read back from the file as newg.
Actually, the ofstream line is somewhat too early and may be misleading. It is only for creating the oarchive and can be safely moved down like the ifstream/iarchive. It could look like that:
// create class instance
const gps_position g(35, 59, 24.567f);
/// ....
// save data to archive
{
// create and open a character archive for output
std::ofstream ofs("filename");
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << g;
// archive and stream closed when destructors are called
}
/// ....
// ... some time later restore the class instance to its orginal state
gps_position newg;
{
// create and open an archive for input
std::ifstream ifs("filename");
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> newg;
// archive and stream closed when destructors are called
}
It is and you may use http://www.boost.org/doc/libs/1_34_0/libs/serialization/doc/index.html. (It is doing even more you expect)
I've got a class outputInterface; that should handle the output (to files) of some data. The data is contained in objects of some custom classes, say dataClassA and dataClassB, that all derive from a common base class dataClassBase.
Now I want the data to be written to different files according to its type. So data of type dataClassA should go to fileA, data of type dataClassB should go to fileB and so on. As this output happens very often I would like the file handles (fileA and fileB) to stay open, i.e. I don't want to open and close the files for the output of each piece of data. One outputInterface object can be expected to exist all the time.
So what I would like to achieve is something like this:
Dynamically associate data of type dataClassA with the file handle fileA etc.
When receiving data of type dataClassA check whether fileA is already connected to a file, if not, open the file.
How can I get this behavior (or least something similar / better)?
I've been thinking of making the file handles static members of dataClassA and dataClassB (or the base class dataClassBase?). But then, how do I take care of closing the files? I would have to somehow keep track of the data types that have actually been used (the files that have actually been opened).
Try something like this:
#ifndef OUTPUTINTERFACE?H
#define OUTPUTINTERFACE?H
#include <string>
#include <fstream>
#include <map>
class DataClass
{
public:
virtual bool WriteData(std::ofstream& FStream) = 0;
};
class DataClass1 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "teletubbies";
}
};
class DataClass2 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "garbage";
}
};
class OutputInterface
{
public:
OutputInterface()
{
}
~OutputInterface()
{
//Release stream pointers
}
template<typename T>
bool WriteData(T& Data)
{
std::string dClassUID = std::string(typeid(T).name);
tFStreamMap::iterator it this->streamMap.find(dClassUID);
std::ofstream* stream = NULL;
if(it != streamMap.end())
{
stream = it->second;
}
else
{
stream = new std::ofstream();
stream->open(dClassUID + ".txt");
streamMap.insert(std::make_pair(dClassUID, stream));
}
Data.WriteData(stream);
}
private:
typedef std::map<std::string, std::ofstream*> tFStreamMap;
tFStreamMap streamMap;
};
#endif
This is just a prove of concept and can be optimized in many ways.
I would rather stick with overloaded functions than with runtime type checks.
This is fairly easy to implement in C++11, using an
std::map<std::type_index, std::ostring*> outputMap. (In C++03, you'll have to
implement the equivalent of std::type_index yourself.) You get the
output stream using outputMap[typeid(*data)]. The only problem is
getting the streams into the map to begin with: you can do something
like:
std::ostream*& destPtr = outputMap[typeid(*data)];
if ( destPtr == NULL ) {
destPtr = new std::ofstream("...");
}
std::ostream& dest = *destPtr;
But from where do you get the filename?
There's also the question of when you close the streams: you can't
normally close an output stream in a destructor, since closing an output
stream is an operation which can fail, and you need to detect and react
to that failure. Probably with an exception, which is why you don't
want to do it in a destructor.
Since the "data" part comes from dataClassBase, you can make a virtual/pure-virtual function 'WriteData` in this class, and let derive class implement it.
The class outputInterface may take objects of type dataClassBase and would directly call WriteData. Other than WriteData you may also add other virtual functions in dataClassBase
You did not mention relationship between outputInterface and dataClassBase