Thread: Abstract classes and operators

  1. #1
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490

    Abstract classes and operators

    Code:
    class Factor {
      void func() =0;
    }
    class Function : public Factor;
    class Variable : public Factor;
    I want to overload the '^' operator so it will return a Factor of the same type of itself. Ie:
    Code:
    Factor operator^(const Factor& x, const double y);
    I don't want to have to overload for every derived class of Factor. Is there anything I can do?

  2. #2
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    The best solution I can come up with right now (assuming all the 'stuff' to be operated on is in Factor, so thats not an issue), is to overload it for each class, but simply call Factor::operator^ and then cast it to the derived type.
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  3. #3
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    (assuming all the 'stuff' to be operated on is in Factor, so thats not an issue)
    yep.

    but simply call Factor:perator^ and then cast it to the derived type.
    I don't understand... if I overload for each class, operator^ wouldn't exist, would it? And even if it did, how would it solve my original problem?

  4. #4
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    He's saying you can overload the operator ^ for Factor, and then overload for each child, but have most of the work be done by Factor::operator^. BUT this can have a big problem, if (as you seem to suggest) Factor::operator^ actually *creates* a new object to return? This would ruin your program.

    If the operations are exactly the same, you may be able to use a nonmember template function?

    However, you might also want to rethink your overall design if you're going to be deriving a large number of classes. Large numbers of derived classes are not usually good, unless you truly need the polymorphism.
    Last edited by Cat; 06-08-2003 at 11:51 AM.

  5. #5
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    If you want a default ^ operator in your Factor class, then do this:

    Code:
    class Factor {
      virtual Factor operator^(const Factor& x, const double y);
    }
    And then you must define a function for it.

    Because this class has no pure virtuall methods, it is not abstract. This way any derived classes of Factor will have default behaviour for the ^ operator. If you want to change the behaviour of the operator in a derived class, you can override it (not overload it).

    If, however, you declare your operator as follows:

    Code:
    class Factor {
      virtual Factor operator^(const Factor& x, const double y) = 0;
    }
    It has a pure virtual method and is an abstract class. The virtual keyword means that the operator method is essentially as a pointer, which you have declared as pointing to zero (null). You must define the operator call in you derived classes, in order to be able to instantiate them, otherwise they will remain abstract.

  6. #6
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812

    On second thoughts...

    Just looking at the parameters in your operator, & what you need is this:

    virtual Factor& operator^(const double& y);

    The most significant change here is that I've removed 'Factor x'. The operator should be operating on the object self (using the 'this' keyword. I presume this is what you want, or you would be better off using a normal function.

    I've made y a const reference, which avoids copying a double over the stack, instead it passes a reference, while the const means it
    cannot be changed.

    Also, I've made the return a reference, which should be used to return self.

    You operator call should do something like this:

    Code:
    Factor& Factor::operator^(const double& y)
    {
      // Do something with y on self (assumes this changes self)
      do_something_function(y);
    
      // Return self result
      return *this;
    }
    OS: Windows XP
    Compilers: MinGW (Code::Blocks), BCB 5

    BigAngryDog.com

  7. #7
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    I'm guessing you don't want to be modifying the original object though... Is this a correct assumption?
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  8. #8
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    Here's a possible solution to your problem:

    Code:
    class A
    {
    public:
        template<typename T>
        T operator^(const double& y)
        {
            A x;
            // Create a new object of type A.
            return T(x);
        }
    };
    
    class B : public A
    {
    public:
        B(const A&) {}
    
        B operator^(const double& y)
        {
            return A::operator^<B>(y);
        }
    };
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  9. #9
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    Originally posted by Zach L.
    I'm guessing you don't want to be modifying the original object though... Is this a correct assumption?
    Correct.
    Because this class has no pure virtuall methods
    My class does have pure virtual methods, although the operator^ doesn't need to be. I already have an operator^= method which modifies the object fine and returns a reference. Even if Factor had no pure virtual methods, I would still be slicing the non-Factor piece off of the object, when all I want to do is modify the Factor pieces.

    There are 4 derived classes from Factor, so overloading for each one is not a problem. The problem is when dealing with Factor* pointers in general.

    I know operator^= works, but sometimes I have a function like this:
    Code:
    Factor& func(const Factor& e) {
      Expression g(3);
      e ^= g; //can't happen: e is const
       //in order to work it correctly, a new copy would have to be allocated, then deleted
      //not very efficient
      //I'd rather do this:
      return e ^ g;
    
    }
    Here's a possible solution to your problem:
    Thanks a lot, I'll check it out.

  10. #10
    Registered User
    Join Date
    Dec 2002
    Posts
    56
    On a side note, if you don't mind my asking, what are you doing? It looks much like something I started a few weeks ago but lost interest in...I was modeling the major mathematical functions, but I couldn't (or didn't try hard enough to) figure out how to model composite functions. Is that anything like what you're doing?

  11. #11
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    Originally posted by roktsyntst
    On a side note, if you don't mind my asking, what are you doing? It looks much like something I started a few weeks ago but lost interest in...I was modeling the major mathematical functions, but I couldn't (or didn't try hard enough to) figure out how to model composite functions. Is that anything like what you're doing?
    Actually, yes. I don't have time to explain it all right now, but if you come up with a list of questions about it, I'll do my best to answer them.

    My source code/executable is in the General forums under the title 'Expression Manipulator'. Version 0.4 is the latest.

  12. #12
    Registered User
    Join Date
    Jan 2002
    Posts
    552
    Zach.L's original suggestion along with Davros modification (removing the first parameter, [edit] and making it virtual [/edit]) will do the trick. All you need is a constructor for Factor& in each of your derived classes (which you probably should have anyways) so the conversion from base class to derived class will work correctly.

    [edit]
    >I want to overload the '^' operator so it will return a Factor of the same type of itself. Ie:

    hmmm, the problem is a bit more complex than it seems at first glance. I dont think you should have each derived class return itself, that is unnecessary. If a function needs the derived version, it should just cast it to that type. If you must have it then templating or just straight coding it in each derived class is probably the only solution
    [/edit]
    Last edited by *ClownPimp*; 06-10-2003 at 11:14 PM.
    C Code. C Code Run. Run Code Run... Please!

    "Love is like a blackhole, you fall into it... then you get ripped apart"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. assigning classes by value
    By m37h0d in forum C++ Programming
    Replies: 9
    Last Post: 12-17-2008, 10:31 PM
  2. Default Class Operators
    By symbiote3 in forum C++ Programming
    Replies: 2
    Last Post: 06-13-2008, 01:44 PM
  3. Operators of abstract classes
    By Thanuja91 in forum C++ Programming
    Replies: 1
    Last Post: 11-02-2007, 05:30 AM
  4. C++ question
    By datainjector in forum C++ Programming
    Replies: 59
    Last Post: 12-20-2002, 09:21 PM
  5. Yuckie Classes
    By tim545666 in forum C++ Programming
    Replies: 1
    Last Post: 01-30-2002, 03:02 AM