Thread: Returning pointers from functions problem.

  1. #1
    Registered User
    Join Date
    Aug 2007
    Location
    U.K.
    Posts
    148

    Returning pointers from functions problem.

    Hi,

    I have been wrestling with this program all day and am looking for some help.

    I have never separated a program up before into separate files (main.cpp, base.h and base.cpp).

    What I'm trying to do is call a function from main() and have that function return a pointer to a new object.

    Once the pointer has been returned, I'm trying to push it into the std::list.

    The problem I've been having is this compile error:

    illegal call of non-static member function
    I have wrote a simple version of my program which reproduces the same problem:

    main.cpp :
    Code:
    #include <iostream>
    #include <list>
    #include <string>
    #include "base.h"
    using namespace std;
    
    int main()
    {
    	typedef list<Base *>BaseList;
    
    	do{
    		char choice;
    		cout << "a) Create then add a base class pointer into the list" << endl;
    		cin >> choice;
    		cin.ignore();
    
    		switch(choice)
    		{
    		case 'a':
    			{
    				//Create an object and return a pointer to that object
    				//(I will be making many of these objects)
    				Base::ReturnPtrToANewBaseClassObject();
    
    				//push the returned pointer onto the std::list
    				BaseList.push_back( ptr );
    
    				cout << "Object now pushed onto list" << endl;
    				break;
    			}
    		default:
    			{
    				cout << "You made an invalid choice" << endl;
    				break;
    			}
    		}
    	}
    	while(true);
    
    	system("pause");
    }
    base.h :
    Code:
    #ifndef BASE_H
    #define BASE_H
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    class Base
    {
    public:
    	//constructor
    	Base(string mystring);
    
    	//Member Functions:
    	Base * ReturnPtrToANewBaseClassObject();//Create an object and return a pointer to it
    
    private:
    
    protected:
    
    	//Data Members common to all objects (abstract base class):
    	string _mystring;
    
    };
    #endif
    base.cpp :
    Code:
    #pragma once
    
    #include <iostream>
    #include <string>
    #include "base.h"
    
    
    //Base class contructor
    
    Base::Base(string mystring)
    {
    	_mystring = mystring;
    }
    
    //Base class function
    Base * ReturnPtrToANewBaseClassObject()
    {
    	//Build an object, and then return a pointer to that object
    	//Wthin main() the pointer will be be pushed into the std:list
    
    	string mystring;
    	cout << "Value? " << endl;
    	getline (cin, mystring);
    
    	//Get a pointer to the new object
    	Base *ptr = new Base(mystring);
    
    	//return the pointer to main()
    	return (ptr);
    }
    Here is what Visual Studio reports when I try to build:

    ------ Build started: Project: myproject, Configuration: Debug Win32 ------
    Compiling...
    main.cpp
    c:\main.cpp(22) : error C2352: 'Base::ReturnPtrToANewBaseClassObject' : illegal call of non-static member function
    c:\base.h(15) : see declaration of 'Base::ReturnPtrToANewBaseClassObject'
    c:\main.cpp(25) : error C2143: syntax error : missing ';' before '.'
    c:\main.cpp(25) : error C2143: syntax error : missing ';' before '.'
    Build log was saved at "file://c:\Debug\BuildLog.htm"
    myproject - 3 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    I have a very similar program working when I use a single main.cpp file, but I want to stop using single files, and this problem has really been holding me back.

    Hope you guys and gals can help me with this.

    Thanks very much!!!

  2. #2
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Boy, let me crack my knuckles and get to it:
    #1
    Code:
    typedef list<Base *>BaseList;
    
    ...
    
    BaseList.push_back( ptr );
    Baselist is a typedef(alias) for an actual object of type list<Base*>. You need to create an instance of that type and use that instance not the typedef when performing the push_back.

    #2
    Code:
    Base::ReturnPtrToANewBaseClassObject();
    Base is a class, not an instance of said class. To call a member function you either need to create an instance of the object first and then call the member function for a particular instance, or you need to make the member function static which means it can be called as you are doing without an actual instance.

    #3 Since you're storing pointers in your list container, you need to iterate through the list and call the destructor for each object manually before the program ends or you'll be leaking memory. Either that, or switch from using a simple pointer to type Base and instead use some form of smart pointer such that this will be taken care of automatically.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  3. #3
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Also,
    Code:
    BaseList.push_back( ptr );
    "ptr" isn't declared in "main". You probably wanted to save the result of the previous line, for example (after fixing the above mentioned errors)
    Code:
    Base* ptr = Base::ReturnPtrToANewBaseClassObject();

  4. #4
    Registered User
    Join Date
    Aug 2007
    Location
    U.K.
    Posts
    148
    Hey hk_mp5kpdw thanks so much!

    I've followed your instructions as best I can, and it is indeed compiling further now.

    here is my code right now:



    main.cpp :
    Code:
    #include <iostream>
    #include <list>
    #include <string>
    #include "base.h"
    using namespace std;
    
    int main()
    {
    	list<Base *>BaseList;
    
    	do{
    		char choice;
    		cout << "a) Create then add a base class pointer into the list" << endl;
    		cin >> choice;
    		cin.ignore();
    
    		switch(choice)
    		{
    		case 'a':
    			{
    				//Create an object and return a pointer to that object
    				//(I will be making many of these objects)
    				Base::ReturnPtrToANewBaseClassObject();
    
    				//push the returned pointer onto the std::list
    				BaseList.push_back( ptr );
    
    				cout << "Object now pushed onto list" << endl;
    				break;
    			}
    		default:
    			{
    				cout << "You made an invalid choice" << endl;
    				break;
    			}
    		}
    	}
    	while(true);
    
    	system("pause");
    }
    base.h :
    Code:
    #ifndef BASE_H
    #define BASE_H
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    class Base
    {
    public:
    	//constructor
    	Base(string mystring);
    
    	//Member Functions:
    	static Base * ReturnPtrToANewBaseClassObject();//Create an object and return a pointer to it
    
    private:
    
    protected:
    
    	//Data Members common to all objects (abstract base class):
    	string _mystring;
    
    };
    #endif
    base.cpp :
    Code:
    #pragma once
    
    #include <iostream>
    #include <string>
    #include "base.h"
    
    
    //Base class contructor
    
    Base::Base(string mystring)
    {
    	_mystring = mystring;
    }
    
    //Base class function
    Base * ReturnPtrToANewBaseClassObject()
    {
    	//Build an object, and then return a pointer to that object
    	//Wthin main() the pointer will be be pushed into the std:list
    
    	string mystring;
    	cout << "Value? " << endl;
    	getline (cin, mystring);
    
    	//Get a pointer to the new object
    	Base *ptr = new Base(mystring);
    
    	//return the pointer to main()
    	return (ptr);
    }
    Here is what Visual Studio reports when I try to build:

    ------ Build started: Project: myproject, Configuration: Debug Win32 ------
    Compiling...
    main.cpp
    c:\main.cpp(26) : error C2065: 'ptr' : undeclared identifier
    Build log was saved at "file://c:\Debug\BuildLog.htm"
    myproject - 1 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    I don't see why the pointer wouldn't be available (undeclared identifier). I expect the function would be returning the pointer to main(), and so using push_back I expected to work.

  5. #5
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Quote Originally Posted by nadroj View Post
    Also,
    Code:
    BaseList.push_back( ptr );
    "ptr" isn't declared in "main". You probably wanted to save the result of the previous line, for example (after fixing the above mentioned errors)
    Code:
    Base* ptr = Base::ReturnPtrToANewBaseClassObject();
    As I said, you call the function, the function returns the value, and you ignore the value. You probably wanted to save it.

  6. #6
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by hk_mp5kpdw View Post
    #3 Since you're storing pointers in your list container, you need to iterate through the list and call the destructor for each object manually before the program ends or you'll be leaking memory. Either that, or switch from using a simple pointer to type Base and instead use some form of smart pointer such that this will be taken care of automatically.
    I meant you'd need to manually delete the pointers stored in the list not call the destructor's as calling delete on the pointer would call the destructor for the object pointed to by the pointer.

    As for the ptr issue you really don't need a pointer variable at all, you can just directly use the return value from the static function call in the push_back function:
    Code:
    BaseList.push_back( Base::ReturnPtrToANewBaseClassObject() );
    
    cout << "Object now pushed onto list" << endl;
    break;
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  7. #7
    Registered User
    Join Date
    Aug 2007
    Location
    U.K.
    Posts
    148
    Everyone thanks so much for your help.

    I have tried everything and am getting a problem with some kind of unresovled external.
    Last edited by Swerve; 03-04-2010 at 11:55 PM.

  8. #8
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    #1 Remove the using namespace std; bit in the header and explicitly qualify any necessary objects that need it with std:: in said header.

    #2 Remove the #ifndef/#define/#endif bits from base.cpp.

    #3 You have a multi-source project (two source files). Are you compiling/linking them both together as part of a project? Your project should have both source files added to it. Your prior build output does not indicate this so maybe you should go ahead and do that.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  9. #9
    Registered User
    Join Date
    Aug 2007
    Location
    U.K.
    Posts
    148
    I got it working in the end.

    Thanks to everyone who helped out.

    this was more about the separation of the files more than anything else.

    It is a nice template for me to use now in the future.
    Last edited by Swerve; 03-04-2010 at 11:54 PM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Here is a good rule to remember:
    When returning a value, let's say you have a box. Inside that box is a value.
    When you write code to return "the box", the compiler actually instead opens the box and returns its contents! So the caller of the function doesn't get the box. The box exists only (for the sake of simplicity, this isn't always the case) in the local function that is called.
    Hence, if the caller wants to save this value, it must create a box and store the value inside it.
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Conversion of pointers to functions
    By hzmonte in forum C Programming
    Replies: 0
    Last Post: 01-20-2009, 01:56 AM
  2. problem using pointers
    By thestien in forum C++ Programming
    Replies: 3
    Last Post: 05-02-2008, 05:02 PM
  3. Passing Structure Pointers to Functions
    By samus250 in forum C Programming
    Replies: 15
    Last Post: 03-20-2008, 03:13 PM
  4. Returning an Array of Pointers to Objects
    By randomalias in forum C++ Programming
    Replies: 4
    Last Post: 04-29-2006, 02:45 PM
  5. Problem with pointers and functions
    By Kheila in forum C++ Programming
    Replies: 5
    Last Post: 10-13-2005, 12:40 PM