How to overload std::ofstream::put() ?

I want to write int16_t values to file. Therefore I tried to overload the std::ofstream::put() method:

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
#include <fstream>
#include <cstdint>

class Ofstream : public std::ofstream
{
public:
    Ofstream( const std::string & s ) : std::ofstream(s) {}
    
    // for little-endian machines
    Ofstream &  put( int16_t val )
    {
        char lsb, msb;
        lsb = (char)val;
        val >>= 8;
        msb = (char)val;
        put(lsb) && put(msb);
        return *this;
    }
    ~Ofstream() {}
};
int main()
{
    int16_t val = 0x1234;
    Ofstream ofile( "test");
    ofile.put(val);
}

With this get a Segmentation fault, so what's wrong with?
Last edited on
Do you know what override specifier do? It check if your function really override something from base class or you only think so.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct A
{
    virtual void foo();
    void bar();
};
 
struct B : A
{
    void foo() const override; // Error: B::foo does not override A::foo
                               // (signature mismatch)
    void foo() override; // OK: B::foo overrides A::foo
    void bar() override; // Error: A::bar is not virtual
};


You don't override base class put() function.


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
#include <fstream>
#include <cstdint>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {}

	// for little-endian machines
	Ofstream& put(int16_t val) override
	{
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		put(lsb) && put(msb);
		return *this;
	}
	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val);
}



I'm newbie on C++. I have to go out now, and will be back in hours or two. If after go back no one c++ Pro don't answer you, I will do.

http://www.cplusplus.com/reference/ostream/ostream/put/
Last edited on
deleted...
Last edited on
Thank you!

But put() must return *this.
Last edited on
1. As I said, your method don't override base put() function it call itself. No write to "test" file at all. Have looping.

Run this code.

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
#include <fstream>
#include <cstdint>
#include <iostream>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {};

	// for little-endian machines
	Ofstream& put(int16_t val)
	{
		std::cout << "I call myself\n";
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		put(lsb) && put(msb);
		return *this;
	}
	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val);
}


2. This code call base class put(char c) and write to "test" file. You can check test file to see that it is not empty. No looping.

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
#include <fstream>
#include <cstdint>
#include <iostream>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {};

	// for little-endian machines
	Ofstream& put(int16_t val)
	{
		std::cout << "I call myself\n";
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		this->std::ofstream::put(lsb) && this->std::ofstream::put(msb);
		return *this;
	}
	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val);
}



3. You ask why LOOPING occur. Because compiler make IMPLICIT CONVERSATION from char to int16_t in this line of code and again call YOUR put(int16_t) function:

 
put(lsb) && put(msb);


If you want to see this make overloading put(char c) function and you will see that it give error because it stop implicit conversation from char to int16_t.

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
#include <fstream>
#include <cstdint>
#include <iostream>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {};

	// for little-endian machines
	Ofstream& put(int16_t val)
	{
		std::cout << "I call myself\n";
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		put(lsb) && put(msb);
		return *this;
	}

	// This is overloading :-)
	Ofstream& put(char c) = delete;

	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val);
}


May be 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
#include <fstream>
#include <cstdint>
#include <iostream>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {};

	// for little-endian machines
	Ofstream& put(int16_t val)
	{
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		this->std::ofstream::put(lsb) && this->std::ofstream::put(msb);
		return *this;
	}
	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val);

Last edited on
But put() must return *this.


Why you think it not return *this?!

Look code:

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
#include <fstream>
#include <cstdint>
#include <iostream>

class Ofstream : public std::ofstream
{
public:
	Ofstream(const std::string& s) : std::ofstream(s) {};

	// for little-endian machines
	Ofstream& put(int16_t val)
	{
		char lsb, msb;
		lsb = (char)val;
		val >>= 8;
		msb = (char)val;
		this->std::ofstream::put(lsb) && this->std::ofstream::put(msb);
		return *this;
	}
	~Ofstream() {}
};
int main()
{
	int16_t val = 0x1234;
	Ofstream ofile("test");
	ofile.put(val).put(val);
}
If all you want to do is write an int16_t in binary then just use the write method.

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
#include <iostream>
#include <fstream>

int main() {
    // open output stream
    std::ofstream fout("output.bin");
    if (!fout) { std::cerr << "error: ofstream\n"; exit(1); }

    // write the int16_t (in current machine's endianness)
    int16_t n = 0x1234;
    fout.write((char*)&n, sizeof n);
    fout.close();

    // open input stream
    std::ifstream fin("output.bin");
    if (!fin) { std::cerr << "error: ifstream\n"; exit(1); }

    std::cout << std::hex;

    // read (and print) individual bytes
    unsigned char ch;
    ch = fin.get();
    std::cout << (int)ch << '\n';
    ch = fin.get();
    std::cout << (int)ch << '\n';

    // read (and print) the int16_t
    fin.seekg(0);  // reset file    
    fin.read((char*)&n, sizeof n);
    std::cout << n << '\n';
}

Last edited on
Thanks for your responses!

Now I realized that I barked up the wrong tree. Because I want to use the binary numbers only at my system in main storage, I realized that the byte order for storing is irrelevant as long as the loading will handle this processing in reverse order.

So I have decided to abandon deriving from fstream and using rather the solution which @dutch presented.
Also, I don't see any documentation saying that put() is a virtual function that can be overidden in the first place.
I realized that the byte order for storing is irrelevant as long as the loading will handle this processing in reverse order.
As long as you're reading and writing on machines with the same endian-ness, this won't be a problem. Otherwise, you're better off seeing if your systems supports ntohl(), htonl(), ntohs() and htons(). These functions convert long (32 bit) and short (16 bit) values from network byte ordering (big endian) to host byte ordering and vice versa. So to write a 16 bit value you'd do
1
2
val = htons(val);
cout.write((const char *)&val, sizeof(val));

and to read it:
1
2
cin.read((char *)&val, sizeof(val));
val = ntohs(val);


These functions are extremely efficient. x86 systems can do the byte swap in a single instruction and obviously for big-endian systems, the functions are nops.
Topic archived. No new replies allowed.