String streams and ifstream

I'm trying to read data from a file that looks like this:
 
1234567890Fred           Murtz                    C00002000.01

...and so on
The first digits are the bank account number, then first name, last name, account type, then balance. I need to read all of these into separate objects with appropriate data types. There is an abstract base class "account" and 4 derived classes for the different account types. I'm getting a memory read error. (reading at 0x000000000)

so in my factory header file I have:
1
2
3
4
5
6
7
8
9
10
11
12
//..includes
void factory(account& a)
{
	std::ifstream s;
	std::string str;
	s.open("H://account2.dat");
	
	std::getline(s, str, '\n');
	std::istringstream(str) >> a.account_code >> a.first_name >> a.last_name >> a.balance;
	std::cout<<a.account_code<<'\n'<<a.first_name;

};


in main I have:
1
2
account& a = simple_account(0,0,0,0);
factory(a);


my base class looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class account
{
protected:
	std::string account_code;
	std::string first_name;
	std::string last_name;
	double balance;

public:
	account(const std::string AC,const  std::string fn,const  std::string ln,const  double bal):
	  account_code(AC),
	  first_name(fn),
	  last_name(ln),
	  balance(bal)
	  {}

	  std::string getAC() const {return account_code;}
	  std::string getFN() const {return first_name;}
	  std::string getLN() const {return last_name;}
	  double getBal() const {return balance;}

	 account(const account& acc):
	  account_code(acc.account_code),
	  first_name(acc.first_name),
	  last_name(acc.last_name),
	  balance(acc.balance)
	  {}

	virtual void monthly_update() = 0;
	virtual char type() = 0;

	friend void factory(account&);
};


derived class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class simple_account: public account
{
public:
	simple_account(const std::string AC, const std::string FN, const std::string LN, const double bal):
	  account(AC, FN, LN, bal)
	  {}

	simple_account(const simple_account& sa):
	  account(sa)
	  {}

	char type()
	{
		return 'A';
	}

	void monthly_update()
	{
		balance = balance * 1.05;
	}
};


can anyone help me out here? I was in a bit of a housing crisis and missed class! I'm not sure getline is the best way to go about doing it, since according to the assignment, "[the factory class] uses that data to dynamically allocate and construct one of the derived objects based on the value of
type" so I have to pull that account type represented by the letter in front of the balance, then call the appropriate account constructor.
closed account (Dy7SLyTq)
do you have to use string stream? i could do this a lot easier with just one string and cctypes
well I was able to use setw and fixed to separate out my variables.

1
2
3
std::getline(s, str, '\n');
	std::istringstream(str) >> std::fixed >> std::setw(10)>> account_code >> first_name >> last_name >> type >> balance;
	std::cout<<account_code<<'\n'<<first_name<<'\n'<<last_name<<'\n'<<type<<'\n'<<balance;


but now I need to construct an account and return it from my factory function, based on its account type.

However, I added this:
1
2
3
4
5
6
	switch(type)
	{
	case 'A':
		simple_account a = simple_account(account_code, first_name, last_name, balance);
		return a;
	}
to my factory function and now it longer outputs the console...??
Last edited on
@DTSCode
I'm starting to wonder about you. You seem to like to make things harder for people.

@The PoloHobo
Yes, using getline() with istringstream is correct. You can omit the third argument to getline() -- it defaults to the newline character.

When using the extraction operator on a string, it scans everything until a whitespace, so account_code becomes "1234567890Fred", which is why you need to use the setw() manipulator. The fixed manipulator does nothing for you here.

BTW, it is not typically safe to use a stringstream temporary like that. More modern compilers can handle it, but I personally think I'll stick to creating a named object first:

1
2
  std::istringstream ss(str);
  ss >> std::setw(10) >> ...

Hope this helps.
closed account (Dy7SLyTq)
what are you talking about? how is my way harder? im not trying to misguide people or argue with you, so if im wrong could you explain why?

[one attempt later]

ok... i see your point. i promise it wasnt intentional, but i was doing it in my head and for some reason it was simpler, but yes it would take too much code to do it my way. forget i said anything
Thanks!

Now I need to fill a vector of pointers with my accounts, but I'm not sure how to get from account& to account*...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "factory.h"
#include <vector>

class manager
{
private:
	std::vector<account*> a;
	account& A;

public:

void fill_vector(account& A)
{
	for(int i = 0; i < 10; ++i) 
	{ 
		A = factory();
		a.push_back(A);  // invalid - no conversion from account to account* exists
	}
}
well I converted all my code to return account*. Now how do I go about accessing these pointers?

I'm not really allowed to use std::cout so I need to call an out put function on these pointers

This aint working:
1
2
3
4
5
6
7
void output()
{
	for(int i = 0; i < 10; ++i)
	{
		a[i].output(); //error: expression must have class type...?
	}
}
Last edited on
@DTSCode
'sallright.

@ThePoloHobo
You changed the definition of factory(). Change it again to return a pointer to an new account.

1
2
3
4
5
6
7
8
#include <algorithm>
#include <iterator>

account* factory();

std::vector<account*> a;

std::generate_n( std::back_inserter( a ), 10, factory );

Hope this helps.
Topic archived. No new replies allowed.