How to make "general" functions

I'm working on a simple program with a friend. I wrote a few I/O functions to plug into the program (they just read from/write to txt files). I'm planning to add them in a header file to be included in the main program.

The program manages collections of items by doing a few CRUD operations. For now, it only stores into memory. There are 3 different structs (to represent the different kind of objects) and 3 vectors (one for each type of struct) to represent the 3 collections.

For each vector of a different struct type (which I've called t_item in this example) I made three I/O functions:

void serialize_item(const string &file_name, t_item &an_item)
Declares a ofstream variable and appends (ios::app) each item field to the txt file. Then calls file.close()

void serialize_all_items(const string &file_name, vector<t_item> &items)
Declares a ofstream variable and overwrites (ios::trunc) file contents. Iterates through vector, writing each struct field to the txt file. Then calls file.close()

void deserialize_items(const string &file_name, vector<t_item> &items)
Declares a local t_item variable and a ifstream variable. Iterates reading the file contents and saving each item field to the t_item variable. When an item is complete, it calls push_back to save it into the vector and goes back to reading the next item from file. Then calls file.close()


The thing is: me and my friend are working separately on different parts of the code. Since he declared all the structs, he got to decide what name to use for each struct and what are the names of the fields (although we both agreed there would be a certain amount of fields in each struct and they would be of certain type, since that's the design we need to implement).

My question now is: is there a way for me to implement the I/O functions without knowing the name of the structs and fields he used? For example, this function:

1
2
3
4
5
6
7
8
void serialize_person(const string &file_name, t_person &a_person)
{
	ofstream personsFile(file_name, ios::app);
	personsFile<< a_person.name << endl;
	personsFile<< a_person.age << endl;
	personsFile<< a_person.gender << endl;
	personsFile.close();
}


My friend could have chosen to name the struct "onePerson" instead of "t_person" and the fields could be "fullName", "age", "sex". But the structure is pretty much the same.

How can I tweak my I/O functions to fit the same structure despite the struct/field names the other programmer chose?
This is where the power and flexibility of classes comes to light.

All you would need to know is what the class is called, which would be provided in the header file for that class. The next thing he/she would have to implement are methods by which you can extract information, such as surname.

So your code would declare an instance of the class, ie: t_person Me. Then you would extract surname with a method in that class, maybe like surname = Me.surName ();. This way it's totally irrelevant to you how it was declared in the class, all you need to know is what method to use defined in the class to get the data.
Thanks!
Is there a way to do this without involving classes? I believe there's struct inheritance but not sure if that would work... We're not allowed to use classes in this project :(

My question now is: is there a way for me to implement the I/O functions without knowing the name of the structs and fields he used?

The name of the structs, fields, and even the names of the functions along with the type and numbers of parameters should be hammered out before you even start coding. Once you have the basic design you can start the code. If during the code writing phase you need to add or change some of the initial design constructs you should contact your co-programmer and work our the changes required, making careful notes as to the where, when, why these changes were made.
We're not allowed to use classes in this project
Then by that logic, you shouldn't be allowed to use structs either, as the basic difference between the two is one's members are public by default and the others aren't.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include	<iostream>
#include	<string>

using namespace std;

struct Sales_data {
	// new members: operations on Sales_data objects
	string isbn() const { return bookNo; }
	double avg_price() const;

// private:
	// data members are unchanged from ยง 2.6.1 (p. 72)
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

int main (void) {
	Sales_data Book;
	Book.bookNo = "What you call it";
	
	cout << Book.isbn () << endl;
}


This compiles and runs as is. Change struct to class and then see what happens. Change back to struct and uncomment "private:".
closed account (48T7M4Gy)
Classes aren't the only things that a header file can contain. In fact header files are a primary tool to the team approach. All the functions and structs can be put in a header file. function headers are more familiar but this is what you do for structs, thanks to http://stackoverflow.com/questions/2732978/c-how-to-declare-a-struct-in-a-header-file



C++, how to declare a struct in a header file:

Put this in a file called main.cpp:

#include <cstdlib>
#include <iostream>
#include "student.h"
using namespace std;
int main(int argc, char** argv) {
struct Student s1;
s1.firstName = "fred"; s1.lastName = "flintstone";
cout << s1.firstName << " " << s1.lastName << endl;
return 0;
}

put this in a file named student.h

1
2
3
4
5
6
7
8
9
#ifndef STUDENT_H
#define STUDENT_H

#include<string>
struct Student {
    std::string lastName, firstName;
};

#endif 


PS function, struct and their field names as jlb above, need to be agreed on. Even the parameter lists and types too. You can't get away from agreement on these without building the proverbial camel that probably won't even get up and grunt. :)
Last edited on
Topic archived. No new replies allowed.