How to implement a smart class convert?

Hello all :P

I started developing the regular "needs" I had with .NET, like split and path classes. I am now working on a "text" class to do all stuff like:
- remove
- startswith
- endswith
- contains
- tolower
- toupper
- replace
- trim(start/end)
- removewidespaces (to replace tabs and 2 spaces to single spaces

This is all working great, and the syntax is:
1
2
string p = "my\\test\\path with spaces";
string s = text(p).replace(" ", "");


Since I want to link commands together, like this:
string s = text(p).replace(" ", "").replace("\\", ".").toupper();

I need some way to convert my class to a string when using the "=" operator.
(because every function returns a "this" pointer and not a string)

So, how can I add this operator to my class, so I can do:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class test
{
	string s;
public:
	test(string val)
	{
		s = val;
	}
};

int main () {	
	string s = test("aaa");
	return 0;
}


Till now I have only seen codes on the web doing the opposite, like:
1
2
test T("aaa");
T = "bbb";


Any help on this would greatly increase my coding skills in c++ :D
Last edited on
You could do this with an "operator std::string()".

1
2
3
4
operator std::string () const
{
    return text.to_str();  // assumes a to_str() method.
}


Or you could just require people to call the to_str() method at the end of the call chain.
yeah, add a to_str() function, just like the string.c_str()
Last edited on
operator std::string () const
{
return text.to_str(); // assumes a to_str() method.
}


Wait..so you can also use convert operators like these? I thought (based on many tutorials) the only allowed operators were +, -, +=, -=, *, /, *=, /=, ==, << etc.

And yeah, that worked like a charm. Thanks everyone for the (fast) reply :P
bergerkiller wrote:
Wait..so you can also use convert operators like these?


Yep. They are called conversion operators. You have to be careful with them, since they can be abused. And they can lead to undesirable behavior. For example, a text object will be silently converted to a string when calling a function that takes a std::string argument is passed a text object. Depending on context, that may be desirable or confusing or cause unintended inefficiencies.
Ok, but that is just completely perfect! Really, this even allowed me to combine my "split" class in my "text" class!

I can now finally do something I always had to do on multiple lines:
s = text(s).tolower().remove(0, 3).replace(" ", "").split("\\").first();
Instead of doing the regular:
1
2
3
4
s = tolower(s);
s = remove(s, 0, 3);
s = replace(s, " ", "");
s = split(s, "\\").first();


I can't thank you enough for this yet simple but oh so useful operator :D
The problem with these conversion operators is that they cannot be separated from the class itself.
If you define such conversions, the user of your code will have no chance to suppress them from happening. In extreme cases this can lead to gotchas like this:

 
std::string s = false;


This type-checks without any warnings...


because every function returns a "this" pointer and not a string


Do you mean these functions modify the original, underlying string object? If so, really bad things are waiting to happen.
Last edited on
Well I haven't noticed any bugs so far...guess this problem occurs with classes using more than 1 member variable :P
BTW: The text class has to act almost similar as the string class, else it would be pretty hard to use it next to regular strings.
The idea is a "string class extension" from what was missing, that I used commonly.
(in .NET I used functions like tolower and split common, but in c++ they are absent)

Here is the header info of the (very large) class and split class:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef TEXT_H
#define TEXT_H

#include <vector>
using namespace std;

class splitlist;

class text
{
private:
	string _s;

public:	
	text(string s);
	string tostring();
	operator string () const;
	text &append(string s);
	text &tolower();
	void tolower(string &s);
	text &toupper();
	void toupper(string &s);
	text &replace(string findstr, string replacestr, bool matchcase = 1);
	text &replace(string replacestr, int offset = 0, int count = -1);
	bool contains(string findstr, bool matchcase = 1);
	bool startswith(string findstr);
	bool endswith(string findstr);
	int length();
	text &trimstart(string trimtext = "");
	text &trimend(string trimtext = "");
	text &trim(string trimtext = "");
	text &removewidespaces();
	text &remove(int offset, int count);
	text &remove(string findstr);
	text &removetill(string findstr, bool matchcase = 1);
	text &reverse(int offset = 0, int count = -1);
	text &insert(string s, int offset = 0);
	text &substring(int offset, int count);
	int indexof(string findstr, bool matchcase = 1);
	int lastindexof(string findstr, bool matchcase = 1);
	double value();
	splitlist split(string delim = " ");
	
};

class splitlist
{
private:
	const string * _s;
	string _delim;
	int _spos;
	int _epos;
	int _cnt;
  
public:
	splitlist(const string &s, string delim = " ");  
	vector<string> all();	  
	vector<string> all(int elemoffset, int elemcount);	  
	vector<string> invall(); 
	vector<string> invall(int elemoffset, int elemcount);
	vector<string> operator()(int rangestart, int rangecount);
	text operator()(int index);
	text at(int index);	  
	text invat(int index);	  
	text first();	  
	text last();	 
	text next(int offset = 1);  
	void skip(int offset = 1);	  
	bool end();	  
	bool begin();	  
	int &count();
};

#endif 


In the text class functions, it modifies it's internal _s string variable, and returns a reference pointer of itself. As long the first instance (text(s as string)) exists, there should be no problem.

Example of one of the text functions:
1
2
3
4
5
text &text::tolower()
{
	for(int i=0;_s[i];i++) if((_s[i] > 64)&&(_s[i] < 91)) _s[i] += 32;
	return *this;
}
Last edited on
Are you doing this "just for fun"? The Boost String Algorithms library provides all of this functionality. And it fits in with more modern C++ programming style, splitting the container (string) from the algorithms that operate on them.

The problem with adding all of these methods to do string manipulation to a class is that it causes you to modify the class every time you want to add new functionality. Separating containers and algorithms as the STL does is considered the best practice with C++. (std::string is held up as "what not to do".)

With that sort of design, you can operate on anything that has an iterator whose value_type is a char: strings, vector<char>, char*, istream_iterator, etc.

The way .NET strings are implemented is fine for that environment. But the C++ way is much more flexible and efficient.

The way .NET strings are implemented is fine for that environment. But the C++ way is much more flexible and efficient


Flame war waiting to happen. You should be more careful making such statements. These designs are simply different, and C# strings has some clear advantages over C++ strings (such as immutability). There is no simple answer.
Haha I used .NET before, and there are some simple reasons why I stepped to c++:
- In .NET every single object is created and initialized from inside. There is no way to prevent loading of (unneeded) parts. This makes .NET slow compared to c++.
- .NET loops are HORRIBLY slow. A for loop takes ages in .NET with only 100000 items; c++ on the other hand can handle millions of cycles in less than a second. I am interested in game design; this loop problem causes unneeded lag when rendering over 1 million object on the scene. Also, physics are impossible to do due to this.
- All or most software teams use c++. This, because c++ is stand-alone and will work on almost any machine. .NET needs a framework, like java does, ruining the idea of "stand alone apps".
- I like building everything from scratch. It's fun when everything is there already, but it kind of ruins the 'pleasure' of coding an entire program when everything is hidden behind .NET statements.

And I bet there are free source codes for this, but I wanted to make my own. A fast one, which can be hard to do. 100.000 cycles of text splitting and only 300 ms duration...that's just great. Also, I wanted to have a "filestream design" in it, to allow a "next" function. Now I can start a split and read every element after another, and stopping when "end" is true. Also, it now allows reverse splitting; starting with the last element.

For example:
You have a very large string containing lots of lines ('\n'). Instead of splitting every single element and storing them to get the last line, I can now use "last" to get it. A lot faster, since it used the 'rfind' string feature.

Of course there are awesome pre-compiled libraries, but making my own allows me more creativity and more performance for my type of usage.

And yeah, flame war about to happen, but this is how I look to it. I must agree; c++ allows more flexibility but code length is a lot longer. You really need to save your work over multiple files, while in .NET this is not the case.
Ok, but are you doing this on purpose?
For me, it seems like lots of wasted effort. Splitting strings? A trivial and rather boring task. No need to reinvent the wheel.


I like building everything from scratch. It's fun when everything is there already, but it kind of ruins the 'pleasure' of coding an entire program when everything is hidden behind .NET statements.


The real fun is building things that have not been ever done before. And this has nothing to do with .NET or C++.


.NET loops are HORRIBLY slow.


LOL, this is like telling that your program is broken because of a bug in the compiler. :D
You obviously did something wrong that you drew such a conclusion. Why MS is marketing .NET as a game programming platform (XNA)? If you were right, they would be idiots.
Last edited on
Flame war commenced...lol xD

Just for starters, are we talking of c++ vs c# or c++ vs vb .net? It DOES make a difference. :P
XNA is built out of c#, and c# reguires the .NET framework to be present.
No framework, no game. This is what troubles me.

What if Windows dies and XNA with it, then you can throw your games in the garbage bin. And what about consoles like playstation and wii? (please no console war)

I understand XNA has the "ow so awesome framework with all awesome features included", but what about being portable and usable in multiple ways?

I have of course checked before on what language suits best. I started off with .NET because it was "simple", but the sooner I released a few apps the sooner people start to complain of:
- missing framework features or wrong version
- OS errors (program works on Windows 7, but not on XP?!)
- bit version errors
- absence of Windows at all

Since c++ is a little closer to c and machine code, I believe it's best to stick with c++. Of course it requires some more code than .NET, but at least it has less 'flaws' that I have encountered...

Interested in your opinion :P

EDIT

About the loops; I made my own 3D graphics engine in .NET, but somehow it took less time to do the "directX render loop" than to loop through my list of custom class objects. For example, I first made it render 800.000 vertices in one go, and then I did it under a loop 8 vertices at a time. Somehow the second go was a lot slower...another explanation for this? The same amount of loops on both sides were performed anyways...
Last edited on
Topic archived. No new replies allowed.