Click here to Skip to main content
14,699,107 members
Please Sign up or sign in to vote.
4.45/5 (4 votes)
See more:
I've wrapped the int class, with a new type: Integer

(I've got most of my operators set up to work just like the original int type does.)

Integer i; // Integer i(100); also works.
i = 100;


I want to be able to do this.

Integer i(100);
int temp = i;


So, is there an operator I can override to accomplish this, it would seem like there is. (I thought it was the "operator=", but, that didn't seem to work, it was still treated as my custom type, and complained about needing a cast to int to work.)

In the end, I just want my wrapped type to work like the original, so that it can be used with any function the original could, and in the same way.

void Add(int a, int b) {.....}

Integer a(100);
Integer b(200);

Add(a, b);


Here is my class implementation.

#pragma once
#include "Object.h"

// Declaration: Integer
class Integer : public Object<int>
{
	public:
		Integer();
		Integer(int source);
		int operator=(int source);
		int operator+(int source);
		int operator+=(int source);
};

// Constructor
Integer::Integer()
{
	Integer::Value = 0;
}

// Constructor
Integer::Integer(int source)
{
	Integer::Value = source;
}

// Operator: Assignment
int Integer::operator=(int source)
{
	Integer::Value = source;
	return Integer::Value;
}

// Operator: Compound Assignment
int Integer::operator+=(int source)
{
	Integer::Value = Integer::Value + source;
	return Integer::Value;
}

// Operator: Addition
int Integer::operator+(int source)
{
	return Integer::Value + source;
}
Posted
Updated 31-Jan-12 7:19am
v2
Comments
Andreas Gieriet 31-Jan-12 18:06pm
   
Hello Joe_Dert,

I hope that this is an academic exercise only, for the excitment to learn something ;-) Reinventing the wheel is very costly, especially if one wants to mimic the behaviour of something existing, like a basic type.

One lesson I did learn is: if you have a class where you are tempted to overload an arithmetic operator, you are likely to reinvent the wheel in some or the other way. The same applies for implementing any kind of string class.

E.g. if you want to do "+" a concatenation of some objects, make a concat() function. The client of your library and your fellow maintainer will thank you!

The abolutely worst thing is *implicit* conversion (as suggested further down). It opens up the box of pandora - "magic" conversion with undesired results will be a nightmere to analyze and fix, especially once the project grows to a decent size...

In a professional project, you will not find any re-invented numeric types or any re-invented string classes (unless one is ignorant about development efforts...).
Maybe these thoughts are worth to consider...

Cheers

Andi
Philippe Mori 31-Jan-12 22:42pm
   
In such case, I think you definitively do not want to define operators like +.

Also, that solution won't easily be expandable to support more types (and in a type-safe manner). For example, if you have a double and want to print it, how will you do? If you have to explicitly tell the target type (say Double instead of Integer).

With templates and polymorphic classes, it would be possible to have a system that would works but it would be complex to built and not be very efficient.

In your case, I think that it would be far better to uses an approche similar to iostream or STL algorithm.

In pratice, it would be preferable to have the following: std::string to_string(int a) { /* implementation here */ } as it is easy to extend that for other types and the compiler will automatically call the appropriate function.

Put those utilities functions in there own namespace then you can selectively use them...
Emilio Garavaglia 1-Feb-12 3:07am
   
Andi, please... Stop coding C++ and use just only Java.

Having a type other then integer that is subject to integer arithmetic is normal if you need a numeric type that doesn't intermix with the other and can overload differently.

About + for concat(), do you know that std::string use + just forn that? If you think STL is somehow stupid, lieave away C++. Otherwist try thinkibng differently.
C++ programmers know operators are overridable, and know c=a+b is a generic expression that is not necessarily the assignment of the result of an arithmetic addiction. Please open your mind (and mindset!)
Your concept of "professional large project" is based on C++99 state of art.
Andreas Gieriet 1-Feb-12 4:29am
   
Thank you for your kind advise ;-)

Please read my comment carefully: It's all about about classes you write yourself.

STL et. al. are very well designed in a meaningful way. It makes sense to have the "+" operator to concatenate these *standard* strings. I'm not challenging that.

I'm challenging the definition of arithmetic operators in *client* classes and especially implicit casts. That's all.

I'm glad that the spirit of C/C++ is "to enable things". This comes with the price to "restrict yourself" to some degree. This "restrict yourself" is what I suggest in my comment above.

Troubles with self-invented numeric types are:

- how the compier deduces argument match with overloaded functions


1. exact match

2. promotion


3. coercion


4. implicit conversion (implicit constructor call)

I'm not even sure if I got it right from memory...

- you can not tell the compiler not to do so.

My advise: Leave that trouble to STL and 3rd party numeric library provides and spend time on your core busines instead.

Cheers

Andi

PS: I don't get your last statement. What do you mean by that?
Emilio Garavaglia 1-Feb-12 4:43am
   
The only thing I understand is a "racism" between my classes and the standard ones.

But both relies on the same core language using the same core features.
And both can be "well designed" (as both can be criticized).

The standard library itself was all but "standard" before the standardization process took place.

At that time was as set of classes written by someone. But since the where classes someone wrote himself (according to your concept) shouldn't be designed that way ...
If I have something that behave as a string, I have the full right to concatenate the same way. I'm just re-using a "well known pattern".

You advise (knowing nothing about who I am, or the OP is) is tendencious: "Leave that trouble to STL and 3rd party numeric library provides and spend time on your core busines instead". My be my business is writing those libraries!

Also consider the "learning curve": if writing a class (considering also the time to test it) takes less than learning how to use a 3rd partly library, where is the trade-off? The answer is all about simple and trivial!
Andreas Gieriet 1-Feb-12 5:17am
   
It's all about where you spend time. If it's worth to one to spend time on creating and debugging numeric classes or his own string classes, then he shall do it! I don't tell you must not do it. It's not black and white: there are cases where it makes sense - in my experience in very rare cases, though.

If you are one of these persons who write 3rd party numeric libraries, then that's fine. My guess: 99.9% of the rest of us don't write such libraries.

Cheers

Andi

PS: You seem to react very emotional on the topic. I'm sorry if I upset you.
[no name] 31-Jan-12 21:24pm
   
I'm basically creating a wrapper for C++, to make it less annoying. :P

Integer i(100);
PrintToConsole(i.ToString());

Is now valid syntax. :)

I'm not re-inventing the wheel, more like, bending it to my will. :D

I'm taking concepts from many languages, and bringing them to C++.

Lot's of generics, C# style syntax, Linq, lambdas, etc,.

For example: Action

// Declaration: Action
class Action
{
private:
typedef void (*Delegate)(void);
Delegate m_delegate;
public:
Action(Delegate d);
void Invoke(void);
};

Gives me code like.. (I have a version that takes a T parameter too.)

void func();
Action a(func);
a.Invoke();

void func(char* c)
Action<*char> a(func)
a.Invoke("Hello World!\n");

I prefer an easy syntax over speed, and it seems to be fine, I'm no C++ master, but, I can handle it, besides, I'm doing it for lulz, and because I can, so it doesn't really matter anyways. (Can't a guy just code something because it looked fun?)

Cheers,

Joe
[no name] 31-Jan-12 22:27pm
   
Well tried! 5!

Use const operator overloading.

operator int()    const { return Value; }
operator double() const { return (double) Value; }
   
Comments
[no name] 31-Jan-12 13:14pm
   
Very nice, works just as expected. :)

Thank you. :D
Philippe Mori 31-Jan-12 20:13pm
   
Although it seems to works... it is really a bad idea to have conversion operator in such case as it hard to predict the type of expression and when predefined operator are used and when user defined operator are used.

For example, if you do Integer a(1); auto b = a = 1; what is the type of auto? You probably expect Integer but with your code, you would get int. It only get worst when other operators and types are used.

The best solution is to force the use of anh explicit function to get the internal value as an int.
[no name] 31-Jan-12 21:44pm
   
I'm well aware of the behavior, its intended, I NEVER want Integer back, I put in int, and get back int.

It's to be treated just like an int, I thought I mentioned that in my OP.

Integer is a container type for ints now, it's based off my abstract Object class, which makes this easy to manage, and extend.

So, while this may generally be a bad idea, I think, it's okay in this case.

But, the whole point of doing this was because the syntax allowed it(operator overloading, etc,.), and I wanted to really push it, and make my own little mini language.
Philippe Mori 31-Jan-12 22:18pm
   
Then why the trouble to define all those operator? Just define the conversion operator and it will almost always be used as an int.

By the way, since operators like + are not symmetric, if a is an int and b an Integer, then A + b would use predefined + while b + a would use your operator.
[no name] 31-Jan-12 22:52pm
   
Because, Integer has friends. (Double, and Float.)

Integer i(100);
Double d(i);

Is valid, and works as expected, I need nothing more from it, I can go between custom types, and default types. (In\Out, like a data stream..)

I'm exploiting operator overloading to create a custom syntax, I'm not trying to properly implement operator overloading.

I understand what I've done.
Philippe Mori 31-Jan-12 23:08pm
   
You cannot pretend to understand what you have done when there are major flaws in your solution (many of them have been exposed in other comments).
[no name] 31-Jan-12 23:44pm
   
How have you exposed flaws in code you don't even have?

What you've seen represents a tiny portion of my code, and it's 10+ hours old no less, I've made many updates since then.

And trust me, it works as intended in all tested scenarios, which are all the ones I intended to support, purposefully, I may add.
JackDingler 1-Feb-12 0:57am
   
LOL!
[no name] 1-Feb-12 1:17am
   
Alright, well, LOL, to you, and good day, etc,.
Stefan_Lang 1-Feb-12 6:21am
   
The above examples work for standard types just as well. I see no need for your classes at all. The only thing is that default streaming may not produce the format you want - but you can just provide functions for that specific purpose, as suggested in solution 3.

Moreover, if you're not even trying to properly implement operator overloading, you shouldn't do it at all. It will only confuse others who in the future may look at your code, or who may want to use your classes (or need to use them, because they're used as argument types for functions in some API they call). That is a huge potential for future bugs.

This is not even a good idea if you're on your own: you'll gather an incomplete understanding of operator overloading and will have a badly designed example that you later may refer to when trying to really take advantage of it. You're doing yourself a disservice in the long run!
[no name] 12-Feb-12 21:18pm
   
I disagree, let me give you an example of why.

I also write mods for video games.

The scripting language of one such game that I mod for was VERY limited, however, I was able to accomplish many things deemed impossible, by simply finding loop holes within existing functionality. (These loop holes are now considered to be the accepted ways of accomplishing similar feats.)

In fact, I've done this for several modding communities, re-invigorating them with new modding possibilities.

So, I'm guessing you would have told Bjarne to just use Simula if he wanted OOP? (Adding classes, etc, to C, is no different than me trying to add an object model to C++..)

Without ppl like me, there would be no innovation, no forward motion, just a million drones doing what some book told them to do.

--

I know that we've already settled this, but, I think this response is warranted.

I believe you're doing a disservice by stifling creativity in private programming ventures.

Sure, this may not be really helpful to someone trying to properly do this, but, as explained, that was never my purpose.

I intentionally abused the mechanics to achieve something otherwise impossible. (Well, without the source code for C++..)

In reality this would be implemented into the basic types themselves, and thus, the hacky implementation would not be necessary.
Stefan_Lang 13-Feb-12 8:01am
   
I intentionally abused the mechanics to achieve something otherwise impossible. (Well, without the source code for C++..)

In reality this would be implemented into the basic types themselves, and thus, the hacky implementation would not be necessary.


Guess what? It already is implemented into the basic types! They already do exactly what wanted! Try it out:
#include <iostream>
void foo(){
int i(100);
double d(i);
std::cout << i << ' ' << d << std::endl;
}</iostream>

Calling foo() prints
100 100

No 'hacky implementation' needed. ;)
[no name] 13-Feb-12 13:06pm
   
I'm well aware of cout.

Your example is NOT what I want, for many reasons.

Reason #1: Your syntax is wrong.

I WANT: i.ToString();

Why:

1. It's more human readable, and easier to remember. (And self describing, which is always nice.)

std::cout << i << ' ' << d << std::endl;

Console::WriteLine(i.ToString() + " " + d.ToString());

2. As a member method(i.ToString), intellisense will pick it up, making it much easier for new programmers to find, and identify.

Why are these things important: It makes your language more accessible, and easier to use.

Reason #2: The object model goes far beyond ToString.

GetType
typeof

Those are possible in C++, but, not as easily, and they require RTTI, my method does not.

I could also add metadata via the object model.

class MetaData
{
std::string Author;
std::string Description;
etc,..
};

class Object : public MetaData
{
};

Regardless, I'm done trying to convince you, believe what you want to believe.

But, I'm telling you, the object model would greatly cleanup C++, eliminating many loose functions, and enhancing usability.

I know why I choose C# over C++, and I'm telling you the solution to many of those problems. (Only a fool would ignore the end users opinion on usability.)
Stefan_Lang 14-Feb-12 4:00am
   
Err....

My answer was not about cout at all, it was about the initialization syntax for int and double. There's no mention of string conversion in the context of this solution, so I never thought of that.

I believe it's about time we stop the discussion now. it just gets more confusing over time, it seems. There's no more advice I can offer anyway. So good luck to your endeavour and have fun. :)
[no name] 14-Feb-12 4:55am
   
"My answer was not about cout at all, it was about the initialization syntax for int and double."

What? This?

int i(100);
double d(100.01);

That? You was showing me that? Yeah, I know how to call constructors.

How is that a solution to my original problem, or for my projects overall goal?

Nevermind, I was just talking out loud...

"I believe it's about time we stop the discussion now."

You ain't lying.

"So good luck to your endeavour and have fun. :)"

Yeah, thanks. :D
JackDingler 31-Jan-12 21:46pm
   
Yeah you're right, you should probably explicitly create 'b' as a type Integer there instead of an auto.
JackDingler 31-Jan-12 21:55pm
   
And if 'a' were a double, you might expect 'b' to be a double, but it would be an int.

I think the lesson here is that if you don't know how operator precedence works, then keep the code simpler.
[no name] 31-Jan-12 22:18pm
   
Not really, it's a container type, for specialized purposes.

Just use the regular types for complex stuff.
JackDingler 1-Feb-12 8:41am
   
Really? I didn't see where he made that clear.
JackDingler 1-Feb-12 8:47am
   
I suppose it's your opinion that the standards committee shouldn't have implemented the std::complex template, using similar operator overloading?

Philippe Mori 1-Feb-12 8:57am
   
Not at all... but for sure they use more appropriate declarations and they don't support implicit convertion to builtin type.

See complex operators
JackDingler 1-Feb-12 9:16am
   
Sure there are cases where this can get you in trouble.

I'll admit, I have a problem with the notion that there can never ever, be a case where this isn't a bad idea. Perhaps that's not what you're saying, but it's that way I read you.
Looks like I'm late to the party, since, apparently, at the very least your original problem was solved, and there also seems to be plenty of advice in that context and in fact a wide scope around it.

What I was missing though after skimming over the various responses (but I may have skipped it), was a word of advice on the declaration and use of arithmetic operators. Others already pointed out the danger of implicit conversion operators, but what I think they failed to mention is that arithmetic operators, too, can cause unwanted conversions.

Consider the following:
class Integer {
   int Value;
public:
   Integer(int v=0) : Value(v) {}
   Integer(const Integer&  v) : Value(v.Value) {}
   Integer& operator=(const Integer&  v) { Value = v.Value; return *this; }
   int operator+=(const Integer& v) { Value += v.Value; return Value; }
   friend int operator+(const Integer& v1, const Integer& v2);
   friend int operator-(const Integer& v1, const Integer& v2);
   friend int operator*(const Integer& v1, const Integer& v2);
   friend int operator/(const Integer& v1, const Integer& v2);
};
void foo() {
   Integer a(3), b(5), c(7), d(11);
   Integer e = (a+b)*(c-d); // (1)
   Integer f = (b+=13)/(c+=d); // (2)
}

(1) this line will first invoke int operator+(const Integer& v1, const Integer& v2) and int operator-(const Integer& v1, const Integer& v2), and then construct e using Integer(int v). Since the result of the first two operators are both int, the multiplication will not invoke int operator*(const Integer& v1, const Integer& v2).

(2) Similarly, this line will invoke Integer(int v=0) to convert 13 to Integer, then invoke int operator+=(const Integer& v) twice, and finally use Integer(int v=0) to construct f. Again, the result type of operator+=(...) prevents the invocation of int operator/(const Integer& v1, const Integer& v2).

Now, if you want to implement some behaviour in Integer that is different from int (and there would be no point if that wasn't your intention), then you may want to control the results of multiplications and divisions just as you do additions and substractions. But, by declaring the result types as int, you implicitely convert intermediate results of your arithmetic operations to int, preventing the use of your own operators.

What you have to do instead is return objects or references to your class, for any operator where it makes sense. You can always add an explicit conversion back to int when you need it - but not before:
class Integer {
   int Value;
public:
   Integer(int v=0) : Value(v) {}
   Integer(const Integer&  v) : Value(v.Value) {}
   explicit operator int() const { return Value; } // (4)
   Integer& operator=(const Integer&  v) { Value = v.Value; return *this; }
   Integer& operator+=(const Integer& v) { Value += v.Value; return *this; }
   friend Integer operator+(const Integer& v1, const Integer& v2);
   friend Integer operator-(const Integer& v1, const Integer& v2);
   friend Integer operator*(const Integer& v1, const Integer& v2);
   friend Integer operator/(const Integer& v1, const Integer& v2);
};
void foo() {
   Integer a(3), b(5), c(7), d(11);
   Integer e = (a+b)*(c-d); // (1)
   Integer f = (b+=13)/(c+=d); // (2)
   int g = (int)f; // (3)
}


Now your operator*(...) and operator/(...) will be called, since the intermediate results are of type Integer.

Note that the result type of operator+=(...) is a reference! This saves you (or the runtime system) the effort of creating a temporary that you otherwise would need as an argument for operator/(...)

(3) Also note that I added the keyword explicit to the conversion operator to prevent unwanted implicit conversion. Now, if you want to convert an Integer to an int, you have to explicitely cast it. That should serve your purpose, but is a cleaner and safer way to do it.

(4) A belated note regarding my suggested use of explicit (thanks to Andreas Gieriet for pointing this out):
Using the keyword explicit on conversion operators is a new feature of C++11. Not all compilers support it (certainly not the older versions).
   
v4
Comments
Andreas Gieriet 1-Feb-12 5:30am
   
Nice an comprehensive descrition. My 5!
Stefan_Lang 1-Feb-12 6:00am
   
Thank you. Although this goes beyond the scope of the original question, I've thought it prudent to point out why operator return types should stay 'in class' - if not for the authors sake, then at least for the sake of others searching the site on the topic of C++ operators.
Andreas Gieriet 1-Feb-12 6:52am
   
Hello Stefan,

I just noticed that this code only compiles with the latest C++11 compiler ("explicit" for the cast operator was only introduced in C++11).

The class would be consistent if both, the cast operator as well as the conversion constructor are defined as "explicit" since both get involved in type deduction if they are implicit. But I guess, then the usage was a bit annoying, since on could not call Integer b(5); b+=10;...

Cheers

Andi
Stefan_Lang 1-Feb-12 7:19am
   
Thanks for the info, I wasn't aware of that. I'll update the solution to point this out.

I do agree that making the constructor explicit as well would be awkward. That is something you should do only when there is a danger of unwanted conversion. E. g. when you define a class Vector with a constructor that has just one integral argument, meant to denote the size of the coefficient array, then you should make that constructor explicit to avoid unwanted conversions from statements such as:

Vector v = 5; // attention: this would call Vector::Vector(int)
Andreas Gieriet 1-Feb-12 7:32am
   
I did not try out, but got that info from a very goob book about the topic (only available in German): C++11: Der Leitfaden für Programmierer zum neuen Standard.
This book is dedicated to the changes from C++98 and covers how the available comiles deal with it.
Philippe Mori 1-Feb-12 8:59am
   
Very nice explanation with concrete example why OP code is problematic.
[no name] 1-Feb-12 13:24pm
   
You're aware that I'm basically doodling in code, for fun, so, yeah.

These comments are getting ridiculous, I'm aware of how it's supposed to be used, and how I'm using it, and a bazillion ways my code could be bettered.

Of course I can use a namespace, etc, I'm aware of this. This code is just for fun, and thus bound for the recycle bin. (I wanted to see if it worked, and it does, pretty much end of story. I use cleaner methods for actual production code. I would use my Action\Func types over this method.)

(You ppl keep pitchforks, and torches on deck, don't you? It's Salem as all hell up in here.)
JackDingler 2-Feb-12 11:41am
   
Discussions of coding styles, and best practices do tend to end up much like religious debates.
[no name] 10-Feb-12 15:04pm
   
Indeed. :)
Stefan_Lang 2-Feb-12 3:53am
   
As I have hinted at at the start of this solution I didn't read all the comments, so at the time I was writing this I didn't know what you're at. Later, I've posted various comments to your replies that reflect this belated realization.

Even if you choose to ignore it, I chose not to change or delete it for the sake of other community members who use the search feature to gather information on the topic of operator overloading.
[no name] 2-Feb-12 15:47pm
   
I just wish that ppl wouldn't jump to conclusions, I came here, and asked for help, true.

However, I was fine with the original solution, that's why I accepted it, but, ppl started questioning what I was doing, why, etc,.

I responded, but that was just an invitation for back seat coding. (I had expected curiosity, there are many better ways of doing this, etc, and I was fine with answering a few questions about it.)

If you wanted to state that this is a bad way of doing it for the record, that's fine too, but, a line was crossed when some of you started implying that I don't know what I'm doing, etc,.

It's all good though, I appreciate the attempts to help, it just wasn't needed, I had wanted to get this implemented quick, to see if the idea was sound, and nothing more.

Btw, some you aren't the targets of my recent comments, one of the first responders for example realized that I was just having some fun here. (Well, he said, he hoped that, that was the case.. :D)

Anyways, some of you just need to slow down and assess the situation a bit better before commenting, and feel free to ask questions. (Ask me to edit my main post with info, so it benefits all it's readers, etc,.)

Peace

---

I should add, I'm generally always willing to learn, however, as mentioned, operator overloading is rarely needed, and creating methods is easier on all involved, so yeah, that's when I lost all interest in operator overloading.
Stefan_Lang 3-Feb-12 5:38am
   
As I see it no one attacked you or 'swung a pitchfork'. I definitely didn't. It's a bit hard to convey intent in typing, but I assure you the comments and solutions all were meant to be helpful, and offered with the best of intents.

The reason people (like me) often offer additional information beyond the scope of the original question is that many areas of programming can be like a quagmire: People not familiar with it ask for help the first time they get stuck, but don't realize the far greater dangers lying ahead. Offering just the little help that these people ask for often leads to them stumbling into a much deeper pit later.

So we try to look beyond the question, to where the author is headed. It may happen, as in this case, that we're looking the wrong way. But you also have to look at the wider use of this forum: questions discussed here will not only lead to a solution for you, but also help many others who later search the site (or the internet in general) for information on this or similar topics.

So please give us a little leeway in taking your question further than you intended - if not for your sake, then for the sake of those following (at least for some fo the way) in your foot prints.

:-)
[no name] 8-Feb-12 17:26pm
   
@Stefan_Lang,

"Although I'm not entirely sure whether the author will appreciate it just as much..."

That's a pretty insulting comment you made. (So, you weren't entirely sure whether I was a moron or not, nice...)

The facts are simple, you made assumptions, they were incorrect, you insulted me in the process, and it could have been avoided by simply wording your responses a little better. (And you weren't the only one.)

Like I said, feel free to expand on ideas, or offer additional help, etc, just, watch the wording, and you won't have issues.
Stefan_Lang 9-Feb-12 4:29am
   
I'm sorry if my wording has left that impression on you, but I assure you that it was not my intention at all to insult you in any way. You are correct, I made false assumptions, and that caused me to offer advice that had little to do with what you were looking for. What I meant to express was my hope ("I'm not sure") that you still would appreciate the advice, even though it would not help you right now. It was not meant to demean your in any way, just my sincere hope that the advice I gave would help someone, eventually. Perhaps you, or perhaps others who happen by later.

English is not my native language as you may have guessed. My vocabulary is far from perfect, and that occasionally leads me to choose words that do not exactly express my meaning. I apologize again if such an ambiguity has caused you distress. I've changed the wording to remove a direct reference to you, it's now:
"Although this goes beyond the scope of the original question"

I hope this will work for you.
[no name] 10-Feb-12 15:02pm
   
@Stefan_Lang,

Don't worry about it. :)

I appreciate your advice, and attempts to help, and I believe that you didn't mean any offense with your comments.

Anyways, sorry about the misunderstanding, etc,.
[no name] 14-Feb-12 5:43am
   
Btw, I tried your solution, are you using an IDE when creating them to verify they're not gibberish?

But, seriously, it won't compile.

I figured I'd give it a try, but it was a no go, so you may want to check that out, I'm sure the future generations will get the gist of it though...
Stefan_Lang 14-Feb-12 5:49am
   
As Andreas Gieriet pointed out in his comment, my use of explicit was only introduced in C++11. It does compile in VC 2010, but not in earlier versions. Sorry for the confusion.
[no name] 15-Feb-12 18:44pm
   
There was more wrong with it than that, missing symbols, and such, and it wouldn't compile in my VC++ 2010 with explicit.

Anyways, I got it working, it took some doing to modify it for my solution, but it seems to work. (It's basically my original code, with a few of your safer methods merged in.)
Stefan_Lang 17-Feb-12 6:23am
   
Yes, seems I've neglected to actually put that code to the test. :-( I also found that explicit conversion operators don't work in VS 2010 either. I'm not sure how I came to make that statement - maybe I misread the C++11 feature list for VS 2010...

Anyway, I've fixed at least the typos in the solution. Thanks for pointing out the problems.
Although that approach might works (even though you still have to learn a lot before having something robust enough for commercial applications), I would not recommand that route.

Something like that would be more in the philosophy of C++:

namespace utilities
{
  std::string to_string(int a) { /* ... */ }
  std::string to_string(double a) { /* ... */ }
}

using namespace utilities;
int a = 1;
double b = 1.1;

// No explicit use of a type like Integer and select appropriate code at compile-time
to_string(a);  
to_string(b);


If you absolutly need polymorphism (I assume that your Object template class has a common class with methods like ToString()), then, you would need a much more complex design... particulary if you want to achieve a behavior similar to C#.
   
Comments
[no name] 1-Feb-12 0:04am
   
Perhaps, but, remember, I'm picking and choosing features from each language, and trying to emulate them as simply as possible.

I took what I needed, made it work, and moved on.

I'm not getting too tied down to C#'s object model, just mimicking it here for standard ToString, GetType, etc,.

There are plenty of ways I could have done this, but, I wanted specific syntax, and usage, and I've wanted to mess with operator overloading, so, here we are.

Btw, ToString is part of Object, it's virtual, Object is an abstract class, just override ToString() where needed, otherwise, the T version in Object works for most types, as seen in Integer.

(Notice that I call Integer.ToString() in my examples, but, it's not defined in Integer, the object model IS that simple, all types derive from Object, Object exposes ToString, which get's overridden in its inheriting classes as needed, for special formatting, ie, [X: 0 Y: 2000], etc,.)
Stefan_Lang 1-Feb-12 6:07am
   
I haven't read all your comments, but from this response I get the very strong impression that your only goal is to mimick C# behaviour, ignoring all the bad side efects this has on performance and memory consumption. If performance and memory is not an issue, why do you use C++ at all? Why not just go with C#?
Stefan_Lang 1-Feb-12 6:05am
   
I agree that in this case your suggestion makes much more sense. All that the Integer class really achieves is eat memory (for using a derived class with virtual functions) and performance. Your suggestion does neither.
[no name] 13-Feb-12 17:11pm
   
Personally, I would rate this solution down, you've had no problem bashing my code, so, let's dissect your solution, and why it's not good.

We'll ignore the fact that this won't even work for most ppl, since many compilers don't support it yet. (It's part of the C++ 11 standard.)

We'll ignore that it's such basic info, it wasn't even worth posting. (Are you seriously telling me how to use namespaces\methods? /face palm)

Down to business, so, what are you suggesting?

That I override an existing standard type, by hiding a needlessly complex re-implementation of itself inside a new namespace? No thanks.

You'd be much better off either using std::to_string as intended(assuming it works logically, I haven't actually used it.), or writing your own implementation.

So assuming one had to write their own,
they'd be better off doing it with a template.

template class T
std::string ToString(const T& source)
{
// You need to discover the type here, then, you need to supply the proper conversion methods for each type, via a switch\if statement.

// Then, I would use stringstream or similar to convert the type to a properly formatted stringified version of itself.

// Of course, you need to catch unknown types, and return some sort of error, etc,.

return result;
}

I didn't bother properly typing out the solution, because the forum would mangle it anyways, but, even this isn't a good solution. (Though, it's better than yours, for too many reasons to explain here.)

One major flaw, is that it's not maintainable, this works fine for one type, or two, or three, etc,.

But, what about thousands of types? Would you want to maintain your Utilities namespace with thousands of conversions? (My OP is about a modification to C++ itself, and thus needs to support millions of users, and user types, your method can't handle it.)

Even my suggested method(in this post) requires you to update the ToString method to add new types, it won't scale well. (At all, actually.)

The object model solution, embeds ToString into every object you create, and is overridable per class, thus, you don't have to maintain some mess of conversions, each author can maintain their own conversion, and keep it hidden in their class implementations.

It's much more manageable on a large scale with the object model in place. (Not to mention, it enforces a standard where every object uses the same method for conversion to a string.)

So, in the future, don't disrespect my code if you can't even understand the full implications of the subject matter, your solution is childish, and fails to address many complex issues.
Philippe Mori 13-Feb-12 20:00pm
   
My code does not requires C++ 11. And if can be implemented in a way that would as maintainable as your solution. One useful trick would be to forward to your root Object class for any class derived from object: std::string to_string(const Object &o) { return o.ToString(); }. Using that approche, you only have to defines functions for builtin type or code you cannot modify.
[no name] 13-Feb-12 22:09pm
   
You used std::to_string, which is part of C++ 11.

See:
http://www.cplusplus.com/articles/EzywvCM9/

Or:
http://en.cppreference.com/w/cpp/string/basic_string/to_string

---

Edit: Actually, I take it back, it does exist in VC++ 2010.

Not sure why it's listed as a C++ 11 feature, it says something about fixing a design flaw in it.

float f(100.01);
std::string s = std::to_string((long double)f);

It's ugly looking, I'll give it that. :D

--

About your latest solution:

That's basically what I did(isn't it?), the only difference is how I stored my data, and that was mainly to get int\double\etc, working as quickly as possible.

Maybe give an example?

class Object
{
// Whatever..
};

To show me exactly what you mean. ?

Regardless, I appreciate your continued input on the subject, thanks. :)
Philippe Mori 13-Feb-12 23:04pm
   
Well, I didn't know that to_string function exists in C++ 11. But defining your own function can be done with any C++ compiler. It just happen that by following the STL naming convention that ToString became to_string (a good practive is to usually follow the conventions already used for naming).
Well the Object would be the one you already used. By having the non member calling the member and assuming that most of your classes derives from Object, you would be able to use the member function most of the time. However for template code, you would typically prefer the non-member if it make sense to use the algorithm on something that does not derive from Object (if you don't use some kind of function object or action).
I uses Visual Studio 11 Preview but my projects also works in VS 2010 and in fact, 2010 is used for official release. I prefer to use the newer version because the designer are less buggy in complex multilanguage projects.
I consider myself as a C++ expert but I am not up to date with all C++03 or C++11 features as I am using C# much more and now with LINQ, it is really powerful. I might eventually uses C++ a bit more if I do some Windows 8 Metro developement.
[no name] 14-Feb-12 0:09am
   
Yeah, I prefer C# myself, and have been using it for most everything lately, and you are absolutely correct, Linq is awesome. :D

I love a lot of C# features(generic collections, etc,.) and it's syntax, but, I also do a lot of low level stuff, ie, DLL injection, function hooking, etc,.

And C++ is the tool for that job. :)

I wouldn't call myself an expert, but, I'm fairly well versed in how it all works. :P

I started with QBasic in my high school computer science class, I'm self taught beyond that. I've used ASM\C#\C\C++\Python\Java\Perl, and many scripting languages(NWScript, etc,.), and things like HTML\Javascript, etc,.

(16 years of programming experience, btw.)

The more I learn, the more I learn that I have more to learn. :P

I only use C\C++ when:

1. Doing low level stuff.

2. Working on a project that was written in C++, and where porting isn't realistic. (Doom3 source code, for example, possible yes, slow, very, I don't have that kind of time.)

Otherwise, I use C#, it's easier, and gives great results, I've never written something in C#, and found that I needed to port to C++ for more speed.

--

Anyways, you seem cool enough, sorry if I got a bit carried away, I just felt a bit insulted by some of your comments.

I tend to take it personally since I'm self taught, it's very hard to learn that much about programming, in so many languages by yourself.

(Sorry, long day, I'm getting tired, and rambling, etc,. Oh, and I almost died last night, I was sick, and had an allergic reaction to some food on top of it, yeah, still feeling rough.)
Philippe Mori 13-Feb-12 23:31pm
   
The flaw in 2010 is probably missing overloads causing useless conversions.
[no name] 14-Feb-12 0:09am
   
Ah, I see.

Check above, I just responded to your last post. :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900