Hey there! Sign in to join this conversationNew here? Join for free
    • Thread Starter
    Offline

    0
    ReputationRep:
    Hey, I'm trying to convert some of my Java work into C++, but I'm having a bit of trouble with the pointers in a singly-linked list (Java, of course, doesn't use any pointers). Here's what I've got so far, but it's not working.

    in MultiplicationList.h:
    Code:
    #ifndef MULTIPLICATIONLIST_H
    #define	MULTIPLICATIONLIST_H
    
    class MultiplicationList {
    public:
        MultiplicationList();
        MultiplicationList(const MultiplicationList& orig);
        virtual ~MultiplicationList();
    
        MultiplicationList(int nNum, MultiplicationList nextList);
        MultiplicationList(int nNum);
    
        int getNum();
        MultiplicationList* getNext();
        int getProduct();
        static void multiplicationListTests();
    private:
        int nNum;
        MultiplicationList* pNextNum;
    };
    
    #endif	/* MULTIPLICATIONLIST_H */
    and in MultiplicationList.cpp:
    Code:
    #include "MultiplicationList.h"
    #include <iostream>
    
    using namespace std;
    
    MultiplicationList::MultiplicationList() {
    }
    
    MultiplicationList::MultiplicationList(const MultiplicationList& orig) {
    }
    
    MultiplicationList::~MultiplicationList() {
    }
    
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList){
        nNum = nNewNum;
        pNextNum = nextList;
    }
    
    MultiplicationList::MultiplicationList(int nNum){
        this->nNum = nNum;
    }
    
    int MultiplicationList::getNum(){
        return nNum;
    }
    
    MultiplicationList* MultiplicationList::getNext(){
        return pNextNum;
    }
    
    int MultiplicationList::getProduct(){
        bool isNext = false;
        try{
            MultiplicationList next = getNext();
            isNext = true;
        }
        catch(string error){
            cout << "error: " << error;
        }
        int product = isNext ? getNum() * getNext().getProduct(): getNum();
        cout << product;
    }
    
    void MultiplicationList::multiplicationListTests(){
        cout << "== multiplicationListTests ==\n\n";
        MultiplicationList third(3);
        MultiplicationList* pThird = &third;
        MultiplicationList second(2, pThird);
        MultiplicationList* pSecond = &second;
        MultiplicationList first(1, pSecond);
        cout << first.getNum() << " " << first.getNext().getNum() << " " << third.getNum() << ".";
        cout << first.getProduct();
        cout << "\n";
    }
    About the isNext part, I'm not sure how to check whether this is null... In Java you can create a new MultiplicationList object and leave that space as null if it is last in the list, but C++ doesn't let me check whether that is the case (or so it seems...), not sure if it lets me create objects like that - don't think so because I made the second constructor taking just an integer.

    Note that the MultiplicationListTests() isn't finished yet, but the first cout (the getNum()s) prints "1 0 3", so getNext() is obviously not working right. The next line doesn't get printed, the program errors.

    Any ideas on where I'm going wrong? Thanks.
    Offline

    1
    ReputationRep:
    From memory C and C++ won't initialise memory you allocate so if you declare a pointer to something but don't set it to point at anything in particular it will just point to something random.

    Also if you're storing any data in a pointer you need to allocate space for what your storing. If it's just a pointer to an object created elsewhere you shouldn't need to allocate space.

    NB: It's been a while since I've written any C++ so I'm a little rusty but I think you might be having issues in that there's no way to tell when you've hit the end of the linked list.
    • Thread Starter
    Offline

    0
    ReputationRep:
    Hey, thanks for your post.

    Could you elaborate on where I need to allocate space or declare a pointer as pointing to something? I don't really see what you mean, as far as I can see, I've done that...

    Edit: Why doesn't the following work?

    Code:
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList){
        nNum = nNewNum;
        pNextNum = nextList;
    }
    
    MultiplicationList MultiplicationList::getNext(){
        return &pNextNum;
    }
    It gives an error on the return statement saying "MultiplicationList.cpp:25: error: conversion from `MultiplicationList**' to non-scalar type `MultiplicationList' requested". I thought the & operator gives what is stored in what the pointer is pointing to, so I don't see why it isn't working...
    Offline

    14
    ReputationRep:
    The convention in C and C++ is to use 0 to mean null. There's usually the "NULL" constant defined which will be 0. So your constructor that takes just a number should also set the pointer to the next item of the list to 0.
    Offline

    16
    ReputationRep:
    You need to use an asterisk to dereference a pointer, not an ampersand. &pNextNum evaluates to the address of the pointer itself, not the value at the address it points to. Try *pNextNum.

    You said in your previous thread that initialising your pointers to NULL reported a type error? Were you initialising pNextNum to NULL or something else? If it's pNextNum and it's not working, I'd try 0 as Psyk suggested, but it sounds like you might be initialising the wrong thing to NULL.
    • Thread Starter
    Offline

    0
    ReputationRep:
    Thanks. This is what I have now (I'll just post the main bits...)

    Code:
    // Constructor
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList){
        nNum = nNewNum;
        pNextNum = nextList;
    
    ...
    
    MultiplicationList MultiplicationList::getNext(){
        return *pNextNum;
    }
    
    int MultiplicationList::getProduct(){
        int product = getNext() != NULL ? getNum() * getNext().getProduct(): getNum();
        cout << product;
    }
    
    ...
    
    void MultiplicationList::multiplicationListTests(){
        MultiplicationList third(3, NULL);
        MultiplicationList* pThird = &third;
        MultiplicationList second(2, pThird);
        MultiplicationList* pSecond = &second;
        MultiplicationList first(1, pSecond);
        cout << first.getNum() << " " << first.getNext().getNum() << " " << third.getNum() << ".";
    Not working at the moment as I have changed getProduct() and it now errors, but before I did that, the last method printed out 1, then some random huge number and then "3". The pointer seems to be pointing to the wrong thing?

    The only error this gives at the moment (that is stopping it from running) is this: "MultiplicationList.cpp:29: error: no match for 'operator!=' in 'MultiplicationList::getNext()() != 0'" No idea why this isn't working...
    Offline

    14
    ReputationRep:
    (Original post by Kodar)
    Thanks. This is what I have now (I'll just post the main bits...)

    Code:
    // Constructor
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList){
        nNum = nNewNum;
        pNextNum = nextList;
    
    ...
    
    MultiplicationList MultiplicationList::getNext(){
        return *pNextNum;
    }
    
    int MultiplicationList::getProduct(){
        int product = getNext() != NULL ? getNum() * getNext().getProduct(): getNum();
        cout << product;
    }
    
    ...
    
    void MultiplicationList::multiplicationListTests(){
        MultiplicationList third(3, NULL);
        MultiplicationList* pThird = &third;
        MultiplicationList second(2, pThird);
        MultiplicationList* pSecond = &second;
        MultiplicationList first(1, pSecond);
        cout << first.getNum() << " " << first.getNext().getNum() << " " << third.getNum() << ".";
    Not working at the moment as I have changed getProduct() and it now errors, but before I did that, the last method printed out 1, then some random huge number and then "3". The pointer seems to be pointing to the wrong thing?

    The only error this gives at the moment (that is stopping it from running) is this: "MultiplicationList.cpp:29: error: no match for 'operator!=' in 'MultiplicationList::getNext()() != 0'" No idea why this isn't working...
    Your problem is the getNext() function doesn't return a pointer, it's returning an actual MultiplicationList object. There's no operator defined to compare a MultiplicationList object to a number, so the compiler doesn't know what getNext() != 0 means.

    This is one of the fundamental differences between C++ and Java. There are different ways of passing objects around. Returning an actual object from a function like your getNext() function means it will make a copy of it and put it on the stack for the calling function to use. So that means if you made a change to that object, you wouldn't actually be changing the one that's in the list.

    You would probably be better off making getNext return a pointer. As it is now your program would crash if you tried to call getNext when pNextNum = 0 because you can't dereference an invalid or null pointer.
    Offline

    16
    ReputationRep:
    (Original post by Psyk)
    You would probably be better off making getNext return a pointer.
    Which leads him back to his original problem of needing to dereference first.getNext() before performing getNum() on it, as per his previous thread.
    • Thread Starter
    Offline

    0
    ReputationRep:
    Thanks guys. I've tried adding a new variable which states whether that part of the list is the last one, but my pointers still aren't working. This runs now, but the output is wrong. For the first getNum() it prints "1", for the next "100", for the next "1079756522" and for getProduct() it prints "4535264"...

    In MultiplicationList.h:
    Code:
    public:
        MultiplicationList();
        MultiplicationList(const MultiplicationList& orig);
        virtual ~MultiplicationList();
    
        MultiplicationList(int nNum, MultiplicationList* nextList, bool lastInList);
    
        int getNum();
        MultiplicationList getNext();
        int getProduct();
        static void multiplicationListTests();
    private:
        int nNum;
        MultiplicationList* pNextNum;
        bool lastInList;
    In MultiplicationList.cpp:
    Code:
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList, bool lastInList){
        nNum = nNewNum;
        pNextNum = nextList;
        this->lastInList = lastInList;
    }
    
    ...
    
    int MultiplicationList::getProduct(){
        return !lastInList ? getNum() * getNext().getProduct() : getNum();
    }
    
    void MultiplicationList::multiplicationListTests(){
        MultiplicationList* pThird = new MultiplicationList(3, NULL, true);
        MultiplicationList* pSecond = new MultiplicationList(2, pThird, false);
        MultiplicationList first(1, pSecond, false);
        cout << first.getNum() << " " << first.getNext().getNum() << " " << first.getNext().getNext().getNum() << ".";
        cout << first.getProduct();
        delete pSecond;
        delete pThird;

    Edit:

    Also, I've started to convert the next question now. This one is a question which used an arraylist in Java, so I've used a vector in C++. It also has an abstract class (I think it was an interface in the Java version) and two subclasses. I need one of my functions to take either of the two subclasses, so I tried putting the abstract class as the parameter and it didn't work. I tried making the parameter a pointer to the abstract class, but it seems to not realise it's a pointer maybe, it says "error: cannot allocate an object of type `AbstractTelephoneCall'". Here's the function, any ideas?

    Code:
    void Bill::addCall(AbstractTelephoneCall* atc){
        billList.push_back(*atc);
    }
    Maybe it thinks the *atc is referring to an AbstractTelephoneCall, not one of its subclasses, but I don't know how to fix this.
    Offline

    14
    ReputationRep:
    (Original post by Kodar)
    Thanks guys. I've tried adding a new variable which states whether that part of the list is the last one, but my pointers still aren't working. This runs now, but the output is wrong. For the first getNum() it prints "1", for the next "100", for the next "1079756522" and for getProduct() it prints "4535264"...

    In MultiplicationList.h:
    Code:
    public:
        MultiplicationList();
        MultiplicationList(const MultiplicationList& orig);
        virtual ~MultiplicationList();
    
        MultiplicationList(int nNum, MultiplicationList* nextList, bool lastInList);
    
        int getNum();
        MultiplicationList getNext();
        int getProduct();
        static void multiplicationListTests();
    private:
        int nNum;
        MultiplicationList* pNextNum;
        bool lastInList;
    In MultiplicationList.cpp:
    Code:
    MultiplicationList::MultiplicationList(int nNewNum, MultiplicationList* nextList, bool lastInList){
        nNum = nNewNum;
        pNextNum = nextList;
        this->lastInList = lastInList;
    }
    
    ...
    
    int MultiplicationList::getProduct(){
        return !lastInList ? getNum() * getNext().getProduct() : getNum();
    }
    
    void MultiplicationList::multiplicationListTests(){
        MultiplicationList* pThird = new MultiplicationList(3, NULL, true);
        MultiplicationList* pSecond = new MultiplicationList(2, pThird, false);
        MultiplicationList first(1, pSecond, false);
        cout << first.getNum() << " " << first.getNext().getNum() << " " << first.getNext().getNext().getNum() << ".";
        cout << first.getProduct();
        delete pSecond;
        delete pThird;
    Try my suggestion to make getNext return a pointer to a multiplication list. Your function declaration should look like this:

    Code:
    MultiplicationList* getNext();
    Then you only need to dereference it right at the point of calling a function on it (which you can do using the -> operator).

    (Original post by Kodar)

    Edit:

    Also, I've started to convert the next question now. This one is a question which used an arraylist in Java, so I've used a vector in C++. It also has an abstract class (I think it was an interface in the Java version) and two subclasses. I need one of my functions to take either of the two subclasses, so I tried putting the abstract class as the parameter and it didn't work. I tried making the parameter a pointer to the abstract class, but it seems to not realise it's a pointer maybe, it says "error: cannot allocate an object of type `AbstractTelephoneCall'". Here's the function, any ideas?

    Code:
    void Bill::addCall(AbstractTelephoneCall* atc){
        billList.push_back(*atc);
    }
    Maybe it thinks the *atc is referring to an AbstractTelephoneCall, not one of its subclasses, but I don't know how to fix this.
    Again your problem is not using pointers. Using the * operator in the push_back function means you are passing the atc object by value. But that doesn't really make sense because the type is abstract. You have to make billList take pointers to AbstractTelephoneCall objects.

    Here's something that might make it easier to understand. Really, Java does have pointers. In Java, all objects are passed by pointer (except for primitive types). That fact is just hidden away from you in Java. So actually using pointers in C++ is equivalent to how you use objects in Java.
    • Thread Starter
    Offline

    0
    ReputationRep:
    Thanks guys, the MultiplicationList one is working now! Using the -> to dereference was what fixed it I think, didn't know that was a way of dereferencing them... Pointers are kinda fun though.

    The other one seems almost done too, but I'm getting what seem to be related errors, hopefully not to do with pointers this time:

    Code:
    Bill.cpp:93: error: no matching function for call to `Bill::Bill(std::string&, std::vector<AbstractTelephoneCall*, std::allocator<AbstractTelephoneCall*> > (&)())'
    
    Bill.cpp:158: error: no matching function for call to `Bill::Bill(std::string&, std::vector<AbstractTelephoneCall*, std::allocator<AbstractTelephoneCall*> > (&)())'
    
    Bill.cpp:165: error: request for member `push_back' in `addCallTestArrayList', which is of non-class type `std::vector<AbstractTelephoneCall*, std::allocator<AbstractTelephoneCall*> > ()()'
    I've tried googling about the allocator part, but can't seem to find anything which helps. I thought I might need to declare that with the vector but that isn't mentioned anywhere, so I guess not. Here's some of my code (some bits excluded):

    In Bill.h:
    Code:
    public:
        Bill(string billPayer, vector<AbstractTelephoneCall*> billList);
    
        void addCall(AbstractTelephoneCall* atc);
        string getBillTotal();
        string toBillString();
        static void BillTests();
    private:
        string billPayer;
        vector<AbstractTelephoneCall*> billList;
    };
    In Bill.cpp:
    Code:
    Bill::Bill(string billPayer, vector<AbstractTelephoneCall*> billList){
        this->billPayer = billPayer;
        this->billList = billList;
    }
    
    void Bill::addCall(AbstractTelephoneCall* atc){
        billList.push_back(atc);
    }
    
    // Stuff from here onwards just used for testing.
    
    vector<AbstractTelephoneCall*> addCallTestArrayList1();
    addCallTestArrayList1.push_back(*dayInstance0);
    addCallTestArrayList1.push_back(*dayInstance15);
    addCallTestArrayList1.push_back(*dayInstance30);
    addCallTestArrayList1.push_back(*eveningInstance0);
    addCallTestArrayList1.push_back(*eveningInstance15);
    addCallTestArrayList1.push_back(*eveningInstance30);
    Bill* addCallBillInstance1;
    addCallBillInstance1 = new Bill(jon, addCallTestArrayList1);
    
    ...
    
    vector<AbstractTelephoneCall*> billArrayListZero();
    string aString = "abcd";
    billInstanceZero = new Bill(aString, billArrayListZero);
    Offline

    16
    ReputationRep:
    Change:
    Code:
    vector<AbstractTelephoneCall*> billArrayListZero();
    To:
    Code:
    vector<AbstractTelephoneCall*> billArrayListZero;
    What you are currently doing by including parentheses (when calling the default constructor of the vector class) is creating a function prototype called billArrayListZero that returns a vector<AbstractTelephoneCall*>. Then trying to pass this function to a function that takes a vector object, which clearly makes no sense. You've done the same thing with addCallTestArrayList1.
    Offline

    14
    ReputationRep:
    (Original post by Planto)
    Change:
    Code:
    vector<AbstractTelephoneCall*> billArrayListZero();
    To:
    Code:
    vector<AbstractTelephoneCall*> billArrayListZero;
    What you are currently doing by including parentheses (when calling the default constructor of the vector class) is creating a function prototype called billArrayListZero that returns a vector<AbstractTelephoneCall*>. Then trying to pass this function to a function that takes a vector object, which clearly makes no sense. You've done the same thing with addCallTestArrayList1.
    That depends where the code is. That's not really clear from what he posted. I assume it's within a function, so the compiler would know it's not a function definition. I think it should recognise both as constructing a new vector object.
    • Thread Starter
    Offline

    0
    ReputationRep:
    Ah, removing those brackets fixed it, thanks! I also removed the *s from the things being added using push_back, not sure why they were there. It's working great now.

    Thanks again!
    Offline

    16
    ReputationRep:
    (Original post by Psyk)
    That depends where the code is. That's not really clear from what he posted. I assume it's within a function, so the compiler would know it's not a function definition. I think it should recognise both as constructing a new vector object.
    I'm pretty sure it's valid to place a prototype (though not a function definition) within a function. Admittedly I have no idea if this is of any practical use, though.
    Offline

    14
    ReputationRep:
    (Original post by Planto)
    I'm pretty sure it's valid to place a prototype (though not a function definition) within a function. Admittedly I have no idea if this is of any practical use, though.
    But you can create objects using this syntax:

    Type variableName(constructor parameters);

    As far as I'm aware omitting the brackets is equivalent to using a constructor that takes no parameters.

    Removing those brackets has solved the problem, I'm just not sure why.
    Offline

    16
    ReputationRep:
    (Original post by Psyk)
    But you can create objects using this syntax:

    Type variableName(constructor parameters);

    As far as I'm aware omitting the brackets is equivalent to using a constructor that takes no parameters.

    Removing those brackets has solved the problem, I'm just not sure why.
    The default constructor is a separate method that is only called when no parentheses are supplied. Including empty parentheses in this way causes the compiler to treat the statement as a function prototype. Trust me on this one
    Offline

    14
    ReputationRep:
    (Original post by Planto)
    The default constructor is a separate method that is only called when no parentheses are supplied. Including empty parentheses in this way causes the compiler to treat the statement as a function prototype. Trust me on this one
    Well that explains it. Didn't realise the default constructor was a special case.
    Offline

    0
    ReputationRep:
    (Original post by Psyk)
    But you can create objects using this syntax:

    Type variableName(constructor parameters);

    As far as I'm aware omitting the brackets is equivalent to using a constructor that takes no parameters.

    Removing those brackets has solved the problem, I'm just not sure why.
    You need to look at the grammer for declarations. In something like:

    Code:
    Type variableName(constructor-parameters);
    Type is a decl-specifier-seq and the variableName(constructor-parameters) forms an init-declarator-list.

    An init-declarator-list is a comma separated list of one or more init-declarator each of which is a declarator (in this case variableName) and an optional initializer.

    The only legal forms of initializer are "= initializer-clause" and "( expression-list )". Most importantly an expression-list is a comma separated list of one or more assignment-expressions.

    This means that an empty pair of parentheses is never a valid initializer in a declaration. Type name(); is always a declaration of a function whether or not it occurs in a function or at namespace scope.

    This doesn't mean that you can't use an empty pair of parentheses as an initializer. It is valid in other contexts such as creating temporaries and in new expressions. E.g.

    Code:
    int main()
        {
            int a = int();
            int* b = new int();
        }
    () doesn't necessarily mean call the default constructor; it means value-initialize so it works for types that don't have constructors like int.

    It is not strictly correct to say that a default constructor is only called when there is no initializer, there are contexts where you supply an initializer and it is called.
 
 
 
Reply
Submit reply
TSR Support Team

We have a brilliant team of more than 60 Support Team members looking after discussions on The Student Room, helping to make it a fun, safe and useful place to hang out.

Updated: December 30, 2010
  • See more of what you like on The Student Room

    You can personalise what you see on TSR. Tell us a little about yourself to get started.

  • Poll
    What newspaper do you read/prefer?
    Useful resources
  • See more of what you like on The Student Room

    You can personalise what you see on TSR. Tell us a little about yourself to get started.

  • The Student Room, Get Revising and Marked by Teachers are trading names of The Student Room Group Ltd.

    Register Number: 04666380 (England and Wales), VAT No. 806 8067 22 Registered Office: International House, Queens Road, Brighton, BN1 3XE

    Quick reply
    Reputation gems: You get these gems as you gain rep from other members for making good contributions and giving helpful advice.