?
Solved

using virtual functions

Posted on 2011-05-09
14
Medium Priority
?
337 Views
Last Modified: 2012-05-11
While writing a class as I found myself writing a lot of if statements in many of the public methods, I decided to create a base class with common functionality and created two derived classes with different behaviour. But I have two functions that are exclusive to the derived classes as below.
class Base {
public:
virtual int func1(class A* pA);
virtual int func2(class B* pB);
};

class DerivedA : public Base {
public:
virtual int func1(class A* pA) { return -1; }
virtual int func2(class B* pB) {
//do something
return 0;}
};

class DerivedB : public Base {
public:
virtual int func1(class A* pA) {
//do something
return 0;}

virtual int func2(class B* pB) { return -1; }

};

Open in new window


So, I am unable to overload a single function as I need different type of parameters. What other alternatives could be used?
0
Comment
Question by:Mydeen Yussouf
  • 6
  • 3
  • 2
  • +2
14 Comments
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 168 total points
ID: 35726232
You mean in some derived classes func1 and func2 might want to take parameters other than class A* and class B*?

1. Well, you could write base functions to include all the combinations of different types.

2. You can use a templated base class: http://www.cplusplus.com/doc/tutorial/templates/

3. You could pass a void* as a parameter and cast it to the appropriate type.

4. You can use a variable argument list with your functions: http://www.cprogramming.com/tutorial/lesson17.html

Probably options 1 or 2 are your best bet.

0
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 168 total points
ID: 35726301
It sounds to me like you're using birtual functions for the wrong reason.

Could you be more specific about your use case ? That should help us to come up with a better approach/design.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35726302
s/birtual/virtual/ heh
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35726320
Two out of three syllables is good enough for me. ;)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35726332
lol. That's a standard I can live up to :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 35726483
Before you do anything else, consider whether your class hierarchy really does make sense. If is rare, if you've designed your classes correctly, that you'll be in a situation where not all your interface makes sense.

If you are sure your design is correct then a good design pattern for this kind of problem, where most of your classes virtual interface makes sense but you can't make it all fit is the Visitor Pattern. Using this pattern you can get from a pointer to the base class back to the actual concrete type by passing a visitor into your class, which is then called back with the concrete type of the dynamic class. You then have an overload in the visitor for the difference concrete types, which changes the program flow based on the concrete type of the original class. See my simple example below.


#include <iostream>

struct MyClass1;
struct MyClass2;
struct MyClass3;

struct Visitor
{
	void visit(MyClass1 const * p) const;
	void visit(MyClass2 const * p) const;
	void visit(MyClass3 const * p) const;
};

struct MyClass
{
	virtual void accept(Visitor const * p) const = 0;

	// other virtual functions can go here
};

struct MyClass1 : MyClass
{
	void accept(Visitor const * p) const
	{
		p->visit(this);
	}

	void func(char *) const
	{
		std::cout << "hello from MyClass1" << std::endl;
	}

	// other virtual functions can go here
};

struct MyClass2 : MyClass
{
	void accept(Visitor const * p) const
	{
		p->visit(this);
	}

	void func(float, double, int) const
	{
		std::cout << "hello from MyClass2" << std::endl;
	}

	// other virtual functions can go here
};

struct MyClass3 : MyClass
{
	void accept(Visitor const * p) const
	{
		p->visit(this);
	}

	void func(int, char) const
	{
		std::cout << "hello from MyClass3" << std::endl;
	}

	// other virtual functions can go here
};

void Visitor::visit(MyClass1 const * p) const
{
	p->func("");
}

void Visitor::visit(MyClass2 const * p) const
{
	p->func(1.1f, 2.2, 0);
}

void Visitor::visit(MyClass3 const * p) const
{
	p->func(0, 'x');
}

void visit(MyClass * p)
{
	Visitor v;
	p->accept(&v);
}

int main()
{
	MyClass1 i1;
	MyClass3 i2;
	MyClass3 i3;

	visit(&i1);
	visit(&i2);
	visit(&i3);
};

Open in new window

0
 
LVL 35

Expert Comment

by:sarabande
ID: 35738157
if class A and class B would be derived from same baseclass X you would need only one virtual function:

virtual int func(class X* pX);

in your classes.

if somewhere you need to make special things when the passed pX points to an A, you could do that again by a virtual function.

class DerivedA : public Base {
public:
virtual int func(class X* pX) { return pX->dospecial(this); }
...

here the dospecial could be a virtual function of class X with an overloaded function in class A.

note, templates do not help for your case as the template type must be known at compile time.

Sara

 
0
 
LVL 1

Author Comment

by:Mydeen Yussouf
ID: 35748483
@sarabande, I agree that approach is more elegant. But the function parameters are so unrelated, I am finding it hard to have one. Hence my hack! thoughts?

      virtual int CreateSession(TSimpleDataSet* ptr) = 0;
      virtual int CreateSession(StreamSocket* ptr) = 0;
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35748569
>> thoughts?

As I asked before : could you describe with a bit more detail what it is that you're trying to achieve ?

For example, why do these functions need to be in the base class ? Why not just put specific functions in the appropriate derived classes ?
0
 
LVL 1

Author Comment

by:Mydeen Yussouf
ID: 35748607
@Infinity08, Basically to use the virtual functions,so I can call the methods using a base class pointer. Both the methods belong to the class Session.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35748763
>> so I can call the methods using a base class pointer.

Yes, but what's the point of that, if the methods aren't implemented by all derived classes ?
0
 
LVL 35

Assisted Solution

by:sarabande
sarabande earned 164 total points
ID: 35749056
if the arguments are unrelated (regarding the function) i would assume a different function name also would be appropriate. you should see that using same name for a function is also a kind of polymorpishm and should only be done if the naming is well. so you never should have a function f or func with different arguments.l but for example for a function 'convert_to_string' it is quite senseful to have unrelated argument types. the point is that the result of the function makes up the relation.

For the CreateSession sample i personally would have two functions CreateSessionBySimpleDataSet and CreateSessionBySocket which may or may not be virtual. i also would assume that one of those functions could be called by the other so that you could make non-redundant code also with two functions.

Sara
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35754519
Taking a closer look, I'm with Infinity08...if you had a base class "Animal" and two derived classes "Cat" and "Dog", it wouldn't make sense to write meow() and bark() as members of Animal - meow() should be a member of the derived class Cat, and bark() should be a member of the derived class Dog.  Likewise, since as you stated I have two functions that are exclusive to the derived classes, then those functions should exist only in the derived classes for which they are appropriate.  However, if meow() and and bark() want to take advantage of some common code defined in the base class, you can include that common code in a member of the base class (e.g. Animal::noise()), and call that member from the more specific Cat::meow() and Dog::bark().

This code might be a little funky, hopefully it'll at least get my point across - maybe Infinity08 can make more sense of my rambling. ;)

class Animal
{
protected:
	virtual void noise()
	{
		// Common code
	}
};

class Cat : public Animal
{
public:
	int meow(double tone, float duration)
	{
		// Meow-specific code

		// Call base class's noise()
		noise();

		// more meow-specific code
	}
};

class Dog : public Animal
{
public:
	int bark(int woofCount)
	{
		// call base class's noise()
		noise();

		// bark-specific code
	}
};

Open in new window


I got interrupted, so it's been a couple hours since I started typing this comment, so forgive me if someone else posted the same thing in the interim...
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35754748
I like the Animal analogy, tgerbert. But I'd take it a bit further and propose an implementation like this that might possibly be more appropriate (depending on the specific needs of olmuser, which I'm still trying to figure out) :
class Animal {
    public :
        virtual void noise() = 0;
};

class Cat : public Animal {
    public :
        void meow(double tone, float duration) {
            // Meow-specific code
        }

        virtual void noise() {
            this->meow(1.2, 3.4f);
        }
};

class Dog : public Animal {
    public :
	void bark(int woofCount) {
            // bark-specific code
	}

        virtual void noise() {
            this->bark(5);
        }
};

Open in new window

0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Suggested Courses

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question