Thread: Homework Problem About Pointers

  1. #1
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57

    Homework Problem About Pointers

    Hi, I am trying to figure out what's wrong with my code here?
    I should overload these two operators using pointers, I know how to overload them without pointers, but I guess I'm making a mistake in my function definition in my implementation file that I cannot catch.

    These are the operators I need to overload and their declaration:

    friend std:stream& operator <<( std:stream& outs, const SodaCan * can);
    friend std::istream& operator >>( std::istream& ins, SodaCan * & can);

    This is my class( SodaCan ) interface:

    Code:
    #ifndef SODACAN_H
    #define SODACAN_H
    #include <iostream>
    #include <string>
    #include <cstdlib>
    using namespace std;
    
    ////
    //// The class SodaCan represents a cup of fizzy drink
    //// Each instance of SodaCan carries its own brand, size and contents value
    ////
    class SodaCan {
    public:
        // the default parameter-less constructor
        SodaCan( );
        // another constructor that takes various arguments
        SodaCan( string brand, int size, int contents );
    
        // think of each of these methods as questions each instance can answer
        bool   isEmpty();
        void   pourInSoda( int amount );
        void   drink( int amount );
        void   setSize( int size );
        int    getSize( );
        string getBrand( );
        void   setBrand( string brand );
        int    getContents( );
    
        friend std::ostream& operator <<( std::ostream& outs, const SodaCan *can );
        friend std::istream& operator >>( std::istream& ins, SodaCan *&can );
    
    private:
        string my_Brand;      /// the kind of fizzy drink
        int    my_Size;       /// the size of the container
                              ///     should never be less than zero
        int    my_Contents;   /// the amount of drink in the container
                              ///     should always be <= my_Size
                              ///     should never be less than zero
    };
    
    #endif

    I can also copy my full implementation file here and the application file, but I don't think it is needed(ask me if you need to see please)

    So here's my definition for the operator <<:

    Code:
     ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         SodaCan *temp;
         temp = new SodaCan;
         *temp = *can;
         if(temp = NULL){
             temp->my_Brand = "NULL";
             temp->my_Contents = 0;
             temp->my_Size = 0;
         }
         
         outs<< temp->getContents() <<" ounces of " <<temp->getBrand() <<" in a "<<temp->getSize()<< " can."<<endl;
        
         delete temp;
         return outs ; 
    }

    without the pointer as the argument of the function, it would have been easy to define the overloaded function:

    Code:
    ostream& operator <<( ostream& os, SodaCan &my_can )
    {     
        os<< my_can.getContents() <<" ounces of " <<my_can.getBrand() <<" in a "<<my_can.getSize()<< " can."<<endl;
        return os ; 
    }

    however, with pointers, I get this error:

    "1>Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main
    1>E:\Users\Ashl7\Desktop\SodaCan2012\Debug\SodaCan 2012.exe : fatal error LNK1120: 1 unresolved externals"

    My first definition was simpler and like this:
    Code:
     ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can."<<endl;
        
         return outs ; 
    }
    but it gives error that : the object "can" has type qualifiers that are not compatible with the member function!!

    Can someone please explain to me what I'm doing wrong, and if there's any link that would help me to learn this issue(overloading >> and << using pointers) please share it with me.
    thanks.
    Last edited by Ashl7; 06-02-2014 at 12:54 AM. Reason: adding info

  2. #2
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Why are you not assuming a valid pointer has been passed to <<?

  3. #3
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    What do u mean by a "valid pointer"?
    My application file looks fine...I have:

    Code:
    SodaCan * ptrCan = new SodaCan( "Coke", 25, 3 );
    SodaCan * nullCan = NULL;
    
    cout << nullCan << endl;
    cout << ptrCan << endl;
    Is there something wrong here?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Don't do this. When using the overloaded operator<< to print a pointer to object, the general expectation is that the value of the pointer will be printed (i.e., the address, typically in hexadecimal notation). Therefore, overload operator<< to print a SodaCan object, and if the user of the class has a pointer to a SodaCan object instead, he/she just needs to dereference the pointer.

    EDIT:
    Do not place using directives at file scope in header files, i.e., get rid of using namespace std; in your header file and qualify string as std::string.

    Note that some of your member functions are not const-correct, e.g., I would expect isEmpty and the getFOO functions to be declared const.

    Also, since you don't seem to actually use anything from <cstdlib> in the header, move that inclusion from the header to where you do use something from <cstdlib>. You can also replace the #include <iostream> with #include <iosfwd>, and then in the source file #include <istream> and #include <ostream>, and then finally in the place where you actually use std::cin and std::cout, #include <iostream>.

    That said:
    Quote Originally Posted by Ashl7
    "1>Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main
    1>E:\Users\Ashl7\Desktop\SodaCan2012\Debug\SodaCa n 2012.exe : fatal error LNK1120: 1 unresolved externals"
    This is a link error. It is basically saying that you declared and called:
    Code:
    std::ostream& operator<<(std::ostream&, const SodaCan&);
    But failed to define it.
    Last edited by laserlight; 06-02-2014 at 02:00 AM.
    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

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by MutantJohn View Post
    Why are you not assuming a valid pointer has been passed to <<?
    As a matter of fact, if you look at the implementation of operator<<(), it IS assuming a valid pointer, since the first operation on that pointer is to dereference it. There is no check to determine if the pointer can be dereferenced. The creation of a temporary does not change that.

    Even worse, the OP clearly assumes operator new yields NULL when it fails, which is not true - an exception will be thrown. Also the check for NULL is incorrect - it is an assignment. So the code assumes the pointer passed is valid, dynamically allocates another object, sets the pointer to NULL, and dereferences the NULL pointer. Fans of undefined behaviour and memory leaks will be delighted.

    Like laserlight said, it is not a good idea to overload operator<<() to accept pointers. Either pass the object to be output by value, or by (preferably const) reference. If the caller has a pointer, the caller can do the checks to ensure the pointer is valid (non-null, etc) and dereference as needed.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Code:
    ostream& operator <<( std::ostream& outs, const SodaCan *can ){
     
         SodaCan *temp;
         temp = new SodaCan;
         *temp = *can;
         if(temp = NULL){
             temp->my_Brand = "NULL";
             temp->my_Contents = 0;
             temp->my_Size = 0;
         }
          
         outs<< temp->getContents() <<" ounces of " <<temp->getBrand() <<" in a "<<temp->getSize()<< " can."<<endl;
         
         delete temp;
         return outs ;
    }
    I love this function. It first creates a new temporary for absolutely no reason, then creates in on the heap for absolutely no reason, then assumes that new returns NULL (really, nullptr) on failure (it does not; it throws an exception), then assigns NULL to the pointer and then dereferences it several times before trying to delete the NULL pointer. Even worse is that it tries to dereference the pointer on purpose when it's NULL.
    Can you explain your mindset to us here? There are a lot of wrongs things and I think we'd like to correct them.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    @Laserlight:
    I know, passing pointers to functions and overloading is troublesome, but this is the way the teacher wants us to do...
    thanks for reminding me about namespace std, and then using std::string!! that was stupid.

    So, basically, the teacher gave us the header file and application file, and wants us to write the implementation file...
    here's my implementation file:
    Code:
    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include "SodaCan.h"
    
    SodaCan::SodaCan( ) {
       my_Brand = "?brand?";
       my_Size = 0;
       my_Contents = 0;
    }
    
    
    SodaCan::SodaCan( string brand, int size, int contents ) {
       my_Brand = brand;
       my_Size = size;
       my_Contents = contents;
    }
    
    
    bool SodaCan::isEmpty() {
       return( my_Contents == 0 );
    }
    
    void SodaCan::pourInSoda( int amount ) {
        my_Contents += amount;
    }
    
    void SodaCan::drink( int amount ) {
        my_Contents -= amount;
    }
    
    void SodaCan::setSize( int size ) {
        my_Size = size;
    }
    
    int SodaCan::getSize( ) {
        return( my_Size );
    }
    
    string SodaCan::getBrand( ) {
        return( my_Brand );
    }
    
    void SodaCan::setBrand( string brand ) {
        my_Brand = brand;
    }
    
    int SodaCan::getContents() {
        return( my_Contents );
    }
    
    ostream& operator <<( ostream& os, SodaCan &my_can )
    {     
        os<< my_can.getContents() <<" ounces of " <<my_can.getBrand() <<" in a "<<my_can.getSize()<< " can."<<endl;
        return os ; 
    }
    
     ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can."<<endl;
        
         return outs ; 
    }
    
    //I have not define it yet, waiting to fix >> first
     istream& operator >>( std::istream& ins, SodaCan *&can ){
    
         return ins;
    }

  8. #8
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    And here's my application file(which I did not write, the teacher did), however, the other overloaded functions( ==,>, < etc.) are written by me:

    Code:
    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <stdexcept>
    #include "SodaCan.h"
    
    
    //operator functions declaration
    const SodaCan operator +(  SodaCan &x1,  SodaCan &x2);
    const SodaCan operator -(  SodaCan &x1,  SodaCan &x2);
    bool  operator >(  SodaCan &x1,  SodaCan &x2);
    bool operator >=(  SodaCan &x1,  SodaCan &x2);
    bool  operator <(  SodaCan &x1,  SodaCan &x2);
    bool  operator <=(  SodaCan &x1,  SodaCan &x2);
    bool  operator !=(  SodaCan &x1,  SodaCan &x2);
    bool  operator ==(  SodaCan &x1,  SodaCan &x2);
    
    int main( ) {
    
    SodaCan myPepsi;
    SodaCan yourDietCoke;
    SodaCan bigGulp;
    SodaCan junk;
    
    bigGulp.setBrand( "Pepsi" );
    bigGulp.setSize( 128 );
    myPepsi.setBrand( "Pepsi" );
    myPepsi.setSize( 12 );
    yourDietCoke.setBrand( "Coke" );
    yourDietCoke.setSize( 12 );
    myPepsi.pourInSoda( 2 );
    yourDietCoke.pourInSoda( 3 );
    bigGulp.pourInSoda( 64 );
    
    /// junk should have 76 ounces
    junk = bigGulp + myPepsi;
    cout << junk;
    
    if (junk > bigGulp) {
      cout <<"junk’s bigger"<< endl;
    }
    if (junk >= bigGulp) {
      cout <<"junk’s bigger or equal"<< endl;
    }
    if (myPepsi < junk) {
      cout<<"myPepsi’s smaller"<<endl;
    }
    if (myPepsi <= junk) {
      cout<<"myPepsi’s smaller or equal"<<endl;
    }
    if (myPepsi != junk) {
      cout <<"myPepsi != junk!"<<endl;
    }
    if (myPepsi == myPepsi) {
      cout <<"equal test works"<<endl;
    }
    
    SodaCan * ptrCan = new SodaCan( "Coke", 25, 3 );
    SodaCan * nullCan = NULL;
    
    // be careful
    cout << nullCan << endl;
    cout << ptrCan << endl;
    
    cin >> ptrCan;
    // notice the difference
    cout << ptrCan << endl; 
    ptrCan->pourInSoda( 10 );
    /// notice the difference
    cout << ptrCan << endl;
    
    delete (ptrCan);
    // why can't I do this???
    // delete( nullCan );
    
    return( 0 );
    
    }
    
    
    
    //operator functions declaration
    
    //every soda can needs three properties: brand, size and content.
    //this funtion returns a SodaCan object, with these three properties
    const SodaCan operator +(  SodaCan &x1, SodaCan &x2){
            
        string firstCan = x1.getBrand();
        string secCan = x2.getBrand();
        string sumBrand;
        int sumSize=0;
        int sumContents=0;
    
        if(firstCan != secCan )
        {
            cout<<"Brands are not the same, it is not possible to do addition!"<<endl;
        }
        else
        {
                sumBrand = x1.getBrand();        //the return object's brand
            
            if(x1.getSize() > x2.getSize()){
                 sumSize = x1.getSize();
            }
            else{
                 sumSize = x2.getSize();            //the retrun object's size
            }
                 sumContents = x1.getContents() +x2.getContents();        //the return onject's content
        }
        
        return SodaCan(sumBrand, sumSize, sumContents); //object is returned
                
            }
    
    const SodaCan operator -(  SodaCan &x1,  SodaCan &x2)
    {
        string firstCan = x1.getBrand();
        string secCan = x2.getBrand();
        string sumBrand;
        int sumSize=0;
        int sumContents=0;
    
        if(firstCan != secCan )
        {
            cout<<"Brands are not the same, it is not possible to do suntraction!"<<endl;
        }
        else
        {
                sumBrand = x1.getBrand();        //the return object's brand
            
            if(x1.getSize() > x2.getSize()){
                 sumSize = x1.getSize();
            }
            else{
                 sumSize = x2.getSize();            //the retrun object's size
            }
                 sumContents = x1.getContents() - x2.getContents();        //the return onject's content
        }
        
        return SodaCan(sumBrand, sumSize, sumContents);
    }
        
    bool  operator >(  SodaCan &x1,  SodaCan &x2)
    {
            return x1.getContents() > x2.getContents();
    }
    
    bool  operator >=(  SodaCan &x1,  SodaCan &x2)
    {
            return x1.getContents() >= x2.getContents();
    }
    
    bool  operator <(  SodaCan &x1,  SodaCan &x2)
    {
            return x1.getContents() < x2.getContents();
    }
    
    bool  operator <=(  SodaCan &x1,  SodaCan &x2)
    {
            return x1.getContents() <= x2.getContents();
    }
    
    bool  operator !=(  SodaCan &x1,  SodaCan &x2)
    {
            return (x1.getContents() != x2.getContents() || x1.getBrand() != x2.getBrand() || x1.getSize() != x2.getSize());
    }
    
    bool  operator ==(  SodaCan &x1,  SodaCan &x2)
    {
            return (x1.getContents() == x2.getContents() && x1.getBrand() == x2.getBrand() && x1.getSize() == x2.getSize());
    }

  9. #9
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    @grumpy:
    I know the definition that you see there was a test, I think this one should work, but it does not:

    Code:
     ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can."<<endl;
        
         return outs ; 
    }


    I know the way I write these codes are not correct, but I'm new to this...if there's a mistake, teach me, instead of mocking me LOL

  10. #10
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Well, no one has to teach you. Most everyone here just likes to help.

    Why doesn't your latest example work? What's it printing? Is it even compiling?

    Saying something doesn't work doesn't help us.

  11. #11
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    I didn't say you "have to"....and teaching is helping
    It does not compile, it says : error C2662: 'SodaCan::getContents' : cannot convert 'this' pointer from 'const SodaCan' to 'SodaCan &'
    > Conversion loses qualifiers
    and here is where it tells me I have to fix:
    Code:
     std::ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can.";
        
         return outs ; 
    }
    I'm still naive about using pointers...but I saw an example in the class the teacher used pointers like the way I did, and it worked!!!!!

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    can is a pointer to const, so you can only invoke functions that are declared const.
    The solution is to add "const" after the functions of all getters, i.e. GetContents, GetBrand, GetSize:
    string GetBrand( ) const;
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    Quote Originally Posted by Elysia View Post
    can is a pointer to const, so you can only invoke functions that are declared const.
    The solution is to add "const" after the functions of all getters, i.e. GetContents, GetBrand, GetSize:
    string GetBrand( ) const;
    Yess, thanks, I remember in the book it said :
    use of const modifier is an all or nothing proposition...that if I use it for one parameter of a particular type, then I should use it for every other parameter of that type that is not changed by the function call.
    Appreciate it. This problem is fixed, however I still get the error I was getting at first, I have not been able to compile it yet...

    1> SodaCan.cpp
    1> Generating Code...
    1> Compiling...
    1> Driver.cpp
    1> Generating Code...
    1>Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main
    1>E:\Users\Ashl7\Desktop\SodaCan2012\Debug\SodaCan 2012.exe : fatal error LNK1120: 1 unresolved externals
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    Last edited by Ashl7; 06-03-2014 at 02:07 AM.

  14. #14
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Wait, try putting inline in front of the definition.

  15. #15
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    Quote Originally Posted by MutantJohn View Post
    Wait, try putting inline in front of the definition.
    what does it do?! never read about it!
    Should I put it in front of all my functions?! or const functions?! or my overloaded function?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Homework Problem help!! Please.
    By arti in forum C Programming
    Replies: 10
    Last Post: 03-22-2013, 06:50 AM
  2. help!!!!!! pointers homework
    By ver_gon89 in forum C++ Programming
    Replies: 17
    Last Post: 11-24-2008, 12:23 AM
  3. homework problem Please Help!
    By alexwink in forum C Programming
    Replies: 24
    Last Post: 10-27-2006, 08:20 AM
  4. Replies: 27
    Last Post: 10-11-2006, 04:27 AM