Thread: A few questions regarding classes

  1. #1
    Registered User Xzyx987X's Avatar
    Join Date
    Sep 2003
    Posts
    107

    A few questions regarding classes

    I ran into two peculiar issues in a program I've been writing regarding class usage. Rather than posting pages upon pages of code, here's a few simplified examples to illustrate the issues:
    Code:
    class foo
    {
    public:
    	foo()
    	{
    		//Do initialization stuff...
    	}
    
    	foo(bool bar)
    	{
    		if(bar)
    			foo();  //Problem here....
    	}
    };
    The problem is that when the version of foo() that takes an argument calls the version that doesn't, the "this" pointer in that function is invalid. I know an easy workaround would be having an extra DoInitialization() member that both versions of the constuctor could call, but I'm still curious as to why the "this" pointer is getting messed up.

    Next issue:
    Code:
    class foo
    {
    public:
    	foo()	{}
    
    	DoStuff()
    	{
    		//Stuff getting done...
    	}
    };
    
    class foobar : public foo
    {
    public:
    	foobar()	{}
    
    	DoStuff()
    	{
    		//Different stuff getting done...
    	}
    };
    
    DoFoobarStuff(foo& foobar)
    {
    	//When you pass this function a class of the foobar type typecast as a foo type, the foobar version
    	//of DoStuff() should get called
    
    	foobar.DoStuff();
    
    	//However,  no matter which type is passed, only the foo version of DoStuff() is ever used
    }
    The question is, how do you make sure the appropriate DoStuff() function gets called corresponding to the actual class that get's passed as an argument, and not the type as percieved by the function that calls DoStuff()? Keep in mind that dynamically determining the actual class type using RTI and casting it to that type first is not an option for me with my current code structure.

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    For your first problem, don't call constructors explicitly. Just make the DoInitialization method.

    For your second problem, that's exactly what the virtual keyword is for. Make DoStuff virtual, and the appropriate version will be called. (Note that you should not actually be typecasting anything, when you pass by reference to the base class, it will only work if you just pass the actual derived object).

  3. #3
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    The constructor creates an object of the class. I really don't see why you even have the second constructor if you aren't even using the argument that you pass to it. I imagine something like this would work, though:
    Code:
    class Base
    {
    public:
      Base(){ /*...*/ }
      Base(int val) { *this = Base();  }
    private:
      //...
    }
    But you would have to be careful to define an assignment operator that performs a deep copy (ie, allocates its own memory rather than copying pointers).

    Edit: Now that I think about it I'm not sure there is ever a good reason to do this...
    Last edited by JaWiB; 11-11-2005 at 02:11 PM.
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  4. #4
    Registered User Xzyx987X's Avatar
    Join Date
    Sep 2003
    Posts
    107
    Quote Originally Posted by Daved
    For your first problem, don't call constructors explicitly. Just make the DoInitialization method.
    Fair enough...

    Quote Originally Posted by Daved
    For your second problem, that's exactly what the virtual keyword is for. Make DoStuff virtual, and the appropriate version will be called. (Note that you should not actually be typecasting anything, when you pass by reference to the base class, it will only work if you just pass the actual derived object).
    Right, somehow I thought that in this case the compiler would have to use the version of DoStuff() from the derived class regardless of whether it was declared virtual because the code it excecuted was defined by the class instance rather than the class type. But, I guess getting that behavior was the point of having virtual functions in the first place. In the past I had only been using virtual for pure virtual functions, and somehow I forgot about it's other purpose. Well, I'm still a little inexperienced in C++, so cut me a little slack here.

    Quote Originally Posted by JaWiB
    The constructor creates an object of the class. I really don't see why you even have the second constructor if you aren't even using the argument that you pass to it. I imagine something like this would work, though:
    Code:
    class Base
    {
    public:
      Base(){ /*...*/ }
      Base(int val) { *this = Base();  }
    private:
      //...
    }
    But you would have to be careful to define an assignment operator that performs a deep copy (ie, allocates its own memory rather than copying pointers).

    Edit: Now that I think about it I'm not sure there is ever a good reason to do this...
    Yea, in my case it would be considerably easier to use a seporate DoInitialization() method than something like that anyway.

  5. #5
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    1)
    The problem is that when the version of foo() that takes an argument calls the version that doesn't, the "this" pointer in that function is invalid.
    It's not invalid. Try this code:
    Code:
    include <iostream>
    using namespace std;
    
    class foo
    {
    public:
    	foo()
    	{
    		cout<<this<<endl
    			<<"Object being created with default constructor."<<endl;
    	}
    
    	foo(bool bar)
    	{
    		cout<<"Object being created with parameterized constructor."<<endl
    			<<this<<endl;
    
    		if(bar)
    			foo();  
    	}
    };
    
    int main() 
    {
    	foo f(true);
    
    	return 0;
    }
    or
    Code:
    #include <iostream>
    using namespace std;
    
    class foo
    {
    public:
    	foo()
    	{
    		cout<<"foo() construtor:"<<endl;
    		DoStuff();  //'this' is used to call DoStuff()
    		
    	}
    
    	foo(bool bar)
    	{
    		cout<<"foo(bool bar) constructor:"<<endl;
    		DoStuff(); //'this' is used to call DoStuf()
    
    		if(bar)
    			foo();
    	}
    
    	void DoStuff()
    	{
    		cout<<"Doing something here."<<endl;
    	}
    };
    
    int main() 
    {
    	foo f(true);
    
    	return 0;
    }
    2)
    Code:
    class foo
    {
    public:
    	foo()	{}
    
    	DoStuff()
    	{
    		//Stuff getting done...
    	}
    };
    
    class foobar : public foo
    {
    public:
    	foobar()	{}
    
    	DoStuff()
    	{
    		//Different stuff getting done...
    	}
    };
    
    DoFoobarStuff(foo& foobar)
    {
    	//When you pass this function a class of the foobar type typecast as a foo type, the foobar version
    	//of DoStuff() should get called
    
    	foobar.DoStuff();
    
    	//However,  no matter which type is passed, only the foo version of DoStuff() is ever used
    }
    Case 1: You pass the function a foo object, and the foo version of DoStuff() is called.

    Case 2: you pass the function a foobar object that is typecast to a foo object. That typecast causes "object slicing": the foobar part of the object is sliced off and discarded.

    When you use a pointer to base type variable, object slicing doesn't occur when you assign the address of a derived object to the pointer. If you dereference the pointer, the foobar object is sliced off once again.

    The virtual keyword in front of a function name tells the compiler you want what's called "dynamic binding". Dynamic binding means you want the version of the function corresponding to the type of the object stored in a variable rather than the version of the function corresponding to the type of the variable. Here is an example:

    foo* p = &myFoobarObject;
    p->DoStuff();

    If DoStuff() is virtual, then dynamic binding causes the DoStuff() version in the class of the object assigned to p, i.e. foobar, to execute. If DoStuff() is not virtual, then "static binding" occurs and the version of DoStuff() in the pointer type, i.e. foo, is called. So, a variable that is of pointer to base class type has both a "static type" and a "dynamic type". The static type is the type of the pointer; the dynamic type is the type of the object assigned to the pointer.

    By the way, all member functions that aren't constructors should specify a return type:

    void DoFoobarStuff(foo& foobar)
    Last edited by 7stud; 11-11-2005 at 04:40 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. questions about classes(implementation files)
    By Link_26 in forum C++ Programming
    Replies: 6
    Last Post: 06-22-2006, 09:48 AM
  2. Classes being able to use other classes functions
    By rainmanddw in forum C++ Programming
    Replies: 6
    Last Post: 01-29-2006, 11:19 AM
  3. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM
  4. Sharing a variable between classes of different .CPP files
    By divingcrab in forum C++ Programming
    Replies: 5
    Last Post: 07-07-2002, 02:57 PM
  5. 2 questions - classes and variables
    By phantom in forum C++ Programming
    Replies: 8
    Last Post: 09-25-2001, 09:22 PM