Thread: Conversion constructor for template class

  1. #1
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248

    Conversion constructor for template class

    Hi everyone,

    Real numbers become complex numbers when the second argument of an operator+, or the argument of an operator +=, is a complex number.

    I have made a type 'Real' as a typedef of 'double', and a type 'Complex' as a class (with all necessary operators). 'Complex' has a one-argument constructor with 'Real', but now I would like to have an operator+, or operator+=, for my 'Real' which converts the real number in a complex number.

    Should I make a separate class 'Real' ? I think that this will have a huge impact on performance, since now all my variables will no longer be written directly on the stack, as is the case (if I'm correct) with the primitive types in C++.

    Thanks for any help!

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    There is no reason why user-defined types couldn't be put on stack, so I don't think there will be a major slow-down.
    Also, to define operator+ for Complex and Real, it is enough if one side of the operator is a user-defined class. The other may well be a built-in type.
    If this is not an exercise, then C++ already has a standard <complex> header.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Real numbers become complex numbers when the second argument of an operator+, or the argument of an operator +=, is a complex number.
    The second requirement does not make sense. You are saying that adding a Complex to the current Real changes its type. I would think that you should simply forbid adding a Complex to the current Real. Alternatively, discard the concept of a Real as a separate type since in mathematics, the set of real numbers is a subset of the set of complex numbers.

    I have made a type 'Real' as a typedef of 'double', and a type 'Complex' as a class (with all necessary operators). 'Complex' has a one-argument constructor with 'Real', but now I would like to have an operator+, or operator+=, for my 'Real' which converts the real number in a complex number.
    Declare operator+ as:
    Code:
    Complex operator+(const Complex& lhs, const Complex& rhs);
    Now, with your Complex constructor that takes a Real, this operator+ will return the sum of a Real and a Complex as a Complex. Likewise, your operator+= will add a Real to the current Complex object.

    Should I make a separate class 'Real' ? I think that this will have a huge impact on performance, since now all my variables will no longer be written directly on the stack, as is the case (if I'm correct) with the primitive types in C++.
    They will still be on the stack since you do not use dynamic memory allocation.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    Alternatively, discard the concept of a Real as a separate type since in mathematics, the set of real numbers is a subset of the set of complex numbers.
    The reason why I use two different types is that I want to use them later on as parameters for template classes. For example, the set of real vector spaces is _not_ a subset of the set of complex vector spaces. They both are vector spaces, but parametrized with a field of either real or complex numbers [Simmons: Topology and Modern Analysis, 1963].

    But yeah, I think it wouldn't be a bad idea to define a type 'Complex' and derive a type 'Real' to stick to mathematics. I have just been discouraged to use derivations (and moreover, dynamic polymorphism), for performance reasons [Vandevoorde&Josuttis, C++ Templates, 2003].

    If this is not an exercise
    Of course! What else should I do on a nice, sunny day as today? Trying to implement a mathematical (linear algebra) library which sticks as close as possible to algebra is a great way to learn..

    But to stick to my question, albeit more general:
    How can I implement a conversion constructor from A to B, if one is of course no derivation of the other and if there is no composition/aggregation?
    Last edited by MarkZWEERS; 05-08-2008 at 08:52 AM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The reason why I use two different types is that I want to use them later on as parameters for template classes. For example, the set of real vector spaces is _not_ a subset of the set of complex vector spaces. They both are vector spaces, but parametrized with a field of either real or complex numbers [Simmons: Topology and Modern Analysis, 1963].
    Yes, in this case they have to be distinct types.

    But yeah, I think it wouldn't be a bad idea to define a type 'Complex' and derive a type 'Real' to stick to mathematics.
    However, even if you do that, it will not solve the impossible operator+= requirement. You simply cannot have a case where:
    Code:
    Complex x;
    Real y; // By inheritance, y is also a Complex object.
    y += x; // y is no longer a Real object.
    Consequently, I think you should simply not provide an operator+= that takes a Complex argument, and also not have a constructor that takes a Complex argument, unless that constructor was declared explicit.

    I have just been discouraged to use derivations (and moreover, dynamic polymorphism), for performance reasons [Vandevoorde&Josuttis,m C++ Templates, 2003].
    I believe it is not so much the use inheritance as the use of virtual functions (i.e., "dynamic polymorphism") that can be a performance problem. Of course, if used correctly and wisely it may not even be a problem to begin with, since it would be an appropriate solution.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I'd just eliminate Real as a separate class. Add a single argument constructor to the Complex class which sets the real part, and leaves the imaginary part at 0.0.

    You could also provide a conversion operator to double, which would just return the real part. There are options for how to deal with the imaginary part. First, you could just ignore it, and hope that the person who is converting to double realizes that data might be lost. Or you could check if the imaginary part is not exactly 0.0 and throw an exception when someone tries to convert a complex to a double.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    How can I implement a conversion constructor from A to B, if one is of course no derivation of the other and if there is no composition/aggregation?
    That would be done via a conversion function, though it may be better to make the conversion explicit via a toComplex() and/or toReal() function, or by providing the appropriate constructors (which should be explicit so as to prevent unintended conversion, as mentioned in my previous post).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    However, even if you do that, it will not solve the impossible operator+= requirement. You simply cannot have a case where:
    Code:
    Complex x;
    Real y; // By inheritance, y is also a Complex object.
    y += x; // y is no longer a Real object.
    But this is exactly why I would like to implement a function (cast constructor or other) which changes the type of the object 'y'. So a kind of a 'static_cast<Complex>(y)', which would be possible if 'Real' derives from 'Complex'.

    You could also provide a conversion operator to double, which would just return the real part.
    This will be a 'friend' function 'real( Complex const&)' or 'imag( Complex const&)'. Converting a complex to a real when the imaginary part is zero might become very tricky: a complex value of a something like ' x + j* _e-214' will not be treated as a real...

  9. #9
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    That would be done via a conversion function
    That's exactly my question: how to do this? I know there are functions like 'type_id' , 'typeof' ,'type_info' but can they also change a type? For example

    Code:
    Real x; // x as real
    typeof(x) = Complex; // x now becomes Complex with zero imaginary part
    Complex z = x; // assuming no copy constructor can be called due to its 'explicit' declaration

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That's exactly my question: how to do this?
    Code:
    class A
    {
    public:
        operator B() const; // Conversion function
    };
    The conversion function to B would return an object of type B. It would be used in any context where an object of type A is casted to type B.

    I know there are functions like 'type_id' , 'typeof' ,'type_info' but can they also change a type?
    No, RTTI is interested in type information, not type conversion.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    Real x; // x as real
    typeof(x) = Complex; // x now becomes Complex with zero imaginary part
    I believe this is something you can't do in C++.

    Code:
    Real x;
    Complex z = x;
    This on the other hand should not cause any problems.

    Anyway, what's the point of converting to and from Complex every time it loses or gains the imaginary part? Why not simply work with Complex objects all along?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  12. #12
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    Why not simply work with Complex objects all along
    Since I think that the type of an object should always be the most "low" one, e.g., a 'double' could also be a 'vector' of size one, but I think it is better to keep it a 'double'. Performance and memory consumption are the practical considerations on top of my religious ones: a summation of two 'Real's should be faster than a summation of two 'Complex's, and the former's storage will be less.

  13. #13
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    You're trying to undermine the concept of type safety.

    You could make a RealOrComplex class, that would store either a real, or a complex object as needed. However, the implementation of such an object would take more memory and cycles than just using complex all the time.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  14. #14
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Real cannot derive from Complex. It does not fulfill the Liskov Substitution Principle. Or in other words, never use derivation for defining a restriction. (That's also the classic Square from Rectangle example.)
    Nor can you use it for defining an extension, actually - deriving Complex from Real is just as wrong.
    You should use derivation to go from more abstract to less abstract. Complex and Real are both concrete, so they cannot derive from each other.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #15
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    Real cannot derive from Complex. It does not fulfill the Liskov Substitution Principle.
    Thanks for this explication, I will read more on this principle. I have already struggled psychologically with the idea of derivations, since if 'Real' derives from 'Complex', a one-argument constructor for 'Complex' with 'Real' as argument type would be impossible. Also, a derived class seemed at a first glance similar to a subset, but then functionality can be added which is in contradiction.


    But hold on, this is what I just found on Wikipedia as a definition of the Liskov Substitution Principle:

    Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.
    This holds for all 'Real' objects when derived from 'Complex' : conjugate( x), imag( x), real( x) and so forth.

    It also holds for all 'Complex' objects if derived from 'Real', the functions mentioned above should just be added.


    I think that the Liskov Substitution Principle should always be satisfied in derivation hierarchies, but is not decisive for the question whether derivation is the right architecture.

    What is the right architecture for the informatics model of a superset/subset structure? Class nesting?
    Last edited by MarkZWEERS; 05-08-2008 at 11:50 AM. Reason: added comments on the principle

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer conversion problems with a copy constructor
    By stanlvw in forum C++ Programming
    Replies: 8
    Last Post: 01-14-2008, 12:06 AM
  2. C++ to C Conversion
    By dicon in forum C Programming
    Replies: 7
    Last Post: 06-11-2007, 08:38 PM
  3. Conversion From C++ To C
    By dicon in forum C++ Programming
    Replies: 2
    Last Post: 06-10-2007, 02:54 PM
  4. Creating a database
    By Shamino in forum Game Programming
    Replies: 19
    Last Post: 06-10-2007, 01:09 PM