Determine Class of Object Being Passed Into Another Class Method

I have the following situation. I have 2 classes; call them ClassA and ClassB.

I have another class; call it Class1. Class1 has several methods that use members from either ClassA or ClassB. However, it has a particular method that needs to know what kind of class is being passed into it (for instance, if I pass an object of ClassA into it, then it does something, but if I pass an object of ClassB into it, then it does something else). Currently, Class1 is blind to the type of class that is being passed into its methods. (I achieved this by having ClassA and ClassB being children classes of a single parent class, and passing in a reference to the parent class inside the methods in Class1.) I need to keep Class1 blind to the type of class that is being passed into its methods, yet I also need to determine the class that is being passed into it for one of its methods. Is this possible to do? If so, how do I go about doing this?

I was thinking that I might need to use this-> or templates, but I'm not sure. Thanks!
A very straightforward way is
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Base{
   virtual string type() = 0;
};

struct A : Base {
  string type() { return "A"; }
};

struct B : Base {
  string type() { return "B"; }
};

void foo(Base *ptr) {
  if(ptr->type == "A") {
     A* aptr = (A*)ptr;
     //...
  } else //...
}


One that needs less typing is
1
2
3
4
5
void foo(Base *ptr) {
   A* aptr = dynamic_cast<A*>(ptr);//returns 0 if ptr is not really an A*
   if(aptr != 0) //...
   else //...
}
I tried the following in my parent class header:

1
2
3
4
5
6
7
#include <string>

class ParentClass
{
public:
     virtual string class_type() = 0;
};


However, my compiler is throwing the following error:
error: 'string' does not name a type

Why am I getting this error? I thought string is a type if you include the string header.
Does typeid not work for you?
I don't even know what typeid does. I'll have to look that one up. I'd like to figure out why my compiler is throwing an error, though.
its because string is part of std namespace, do std::string
Good deal. using namespace std; took care of that. One more question. How do I call a function (from main.cpp) that has a pointer as an argument?

For instance, my function (in my Class1 cpp file) is:
1
2
3
4
5
6
7
8
9
10
11
void Class1::function(ParentClass *ParentClass_pointer)
{
     if (ParentClass_pointer->class_type == "ClassA")
     {
          // do stuff given that we have an object of ClassA
     }
     else
     {
          // do stuff given that we have an object of ClassB
     }
}


In main.cpp, do I call it as such?:
 
Class1_object.function(&ChildClass_object); // send in an object of ClassA or ClassB 
Both storing a type-identifying value and dynamic_cast/typid using RTTI are signs of poor design.

From what you said, function overloading should do the trick--although, you later mentioned that Class1 had to remain "blind" so that may not fit your requirements.

You could also approach this using template specialization.

If you provide concrete examples, we can probably identify more options involving some redesign.
Last edited on
If you have to know the type of an object for anything other than serialization, that's most likely a design flaw. As stated above, we need a fully explained and demonstrated example to further help you.
Here it is with overloaded methods:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

struct ClassA {}; 
struct ClassB {}; 

struct Class1 {
    void f( const ClassA & obj ) { cout << "ClassA" << endl; }
    void f( const ClassB & obj ) { cout << "ClassB" << endl; }
};

int main() {

    ClassA a;
    ClassB b;

    Class1 c;
    c.f( a );
    c.f( b );

    return 0;
}
ClassA
ClassB


Here it is with template specialization:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

struct ClassA {}; 
struct ClassB {}; 

struct Class1 {
    template< typename Class >
    void f( const Class & obj ) { cout << "something else" << endl; }
};

template<> void Class1::f( const ClassA & obj ) { cout << "ClassA" << endl; }
template<> void Class1::f( const ClassB & obj ) { cout << "ClassB" << endl; }

int main() {

    ClassA a;
    ClassB b;

    Class1 c;
    c.f( a );
    c.f( b );

    return 0;
}
ClassA
ClassB


Even still, if the derived classes don't model the "is a" relationship (meaning one of them has extra capability) some redesign may be preferred.
Last edited on
Here are the relevant files in my actual program:

The class that needs to operate on objects of the child classes:
binomial_tree.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef BINOMIAL_TREE_H_
#define BINOMIAL_TREE_H_

#include "option.h"
#include "Stock.h"

// creates a binomial tree for any type of option passed to it

class binomial_tree
{
private:
	double option_price;
public:
	// constructor:
	binomial_tree(int N_bucket);

	// data members:
	int N; 			// the number of periods in the tree
	double dt;		// the size of a time period, given N and T
	double u;		// the up factor
	double d;		// the down factor
	double disc;	// the constant discount factor across each time period
	double p;		// the probability of an up move in the tree

	// methods:
	void parameters_calculator(option &option_ref, Stock &Stock_ref);	// calculate the parameters
	void price_calculator(option &option_ref, Stock &Stock_ref, option *option_pointer);	// calculate the price of the option
	void set_price(double);	// mutator
	double get_price();		// accessor
};

#endif 


binomial_tree.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "binomial_tree.h"
#include <math.h>		// used for exp, sqrt, and pow
#include "option.h"
#include "Stock.h"
#include <map.h>

// constructor:
binomial_tree::binomial_tree(int N_bucket) : N(N_bucket)
{
	// set the data members in case the methods are not called explicitly
	dt = 0;
	u = 0;
	d = 0;
	disc = 0;
	p = 0;
}

//methods:

// calculate the necessary parameters:
void binomial_tree::parameters_calculator(option &option_ref, Stock &Stock_ref)
{
	dt = option_ref.T/N;				// the size of a time period
	u = exp(Stock_ref.sigma*sqrt(dt));	// the up factor
	d = 1/u;							// the down factor
	disc = exp(-option_ref.r*dt);		// the discount factor
	p = (1/disc - d) / (u - d);			// the risk-neutral probability of an up move in stock price
}

void binomial_tree::set_price(double option_price_temp)
{
	option_price = option_price_temp;
}

double binomial_tree::get_price()
{
	return option_price;
}

// calculate the price of the option at time 0 using a binomial tree model:
void binomial_tree::price_calculator(option &option_ref, Stock &Stock_ref, option *option_pointer)
{
	// I have adapted a code for pricing a call option that I found on http://www.ma.utexas.edu/users/nringer/pricing.html

	double S[N + 1];	// array for the stock price at time T
	S[0] = Stock_ref.getValue()*pow(d,N);	// let the first element be the lowest possible stock price

	// build the rest of the array for the stock price at time T
	for(int i = 1; i <= N; i++)
	{
		S[i] = S[i - 1]*u/d;	// substitute a d for a u as we go up the array
	}

	// compute the value of the option for all end state values of the stock price (at time T)
	// V[i][j] is the option price for j up moves of the stock price at time i
	map<int, double> V[N + 1];
	for(int j = 0; j <= N; j++)
	{
		if ((option_pointer->class_type == "AC") || (option_pointer->class_type == "EC"))
		{
			// a call has payoff max(S - K, 0)

			double a = S[j] - option_ref.K;
			if (a > 0)
			{
				V[N][j] = a;
			}
			else
			{
				V[N][j] = 0;
			}
		}
		else
		{
			// a put has payoff max(K - S, 0)

			double b = option_ref.K - S[j];
			if (b > 0)
			{
				V[N][j] = b;
			}
			else
			{
				V[N][j] = 0;
			}
		}
	}

	// discount the option values at each state for a given time down to the previous time
	for (int i = N - 1; i >= 0; i--)
	{
		for (int j = 0; j <= i; j++)
		{
			// the up stock price is at position j + 1; the down move is at position j
			V[i][j] = disc*(p*V[i + 1][j + 1] + (1.0 - p)*V[i + 1][j]);
		}
	}

	set_price(V[0][0]);	// set the option price
}


The parent class of my children classes:
option.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef OPTION_H_
#define OPTION_H_

#include "Asset.h"
#include <string>
using namespace std;

class option : public Asset
{
public:
	// constructor (calling format is: t, K, T, r):
	option(double t_dummy, double K_dummy, double T_dummy, double r_dummy);

	// data members:
	double t;		// present time
	double K;		// option strike
	double T;		// maturity date
	double r;		// constant interest rate (continuously compounded, per year)

	// methods:
	double cum_dist_normal(double);	// compute the cumulative distribution of Z (same for call and put)
	virtual double getPayout(double, double) = 0; // return the payout, given a spot price and a time
	virtual string class_type() = 0; // set the class type
};

#endif 


An example child class of option parent class (there are 4 child classes in all):
AmericanCall.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef AMERICANCALL_H_
#define AMERICANCALL_H_

#include "option.h"
#include "Stock.h"
#include <string>
using namespace std;

// an American call option

class AmericanCall : public option
{
public:
	// constructor (calling format is: t, K, T, r):
	AmericanCall(double t_holder, double K_holder, double T_holder, double r_holder);

	// methods:
	double getValue(); 					// return the American call value
	string class_type();				// return the class type ("AC")
};

#endif 


AmericanCall.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "AmericanCall.h"
#include "Stock.h"
#include <string>
using namespace std;

// constructor (calling format is: t, K, T, r):
AmericanCall::AmericanCall(double t_bucket, double K_bucket, double T_bucket, double r_bucket) : option(t_bucket, K_bucket, T_bucket, r_bucket)
{

}

// methods:

// return the American call value
double AmericanCall::getValue()
{
	return 0;
}

string AmericanCall::class_type()
{
	return "AC";
}


The relevant lines from main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
	// create a European Call:
	EuropeanCall ECb_object(0, 105, 1.5, 0.09);
	// create a Stock and set its price:
	Stock Stockb_object(0.35, 0);
	Stockb_object.setValue(105);	// this makes the ECb_object ATM
	// calculate the European Call's price via Black-Scholes:
	ECb_object.BlackScholesValue(Stockb_object);
	cout << "Black-Scholes: C = $" << ECb_object.getValue() << endl;
	// determine the European Call's price via the binomial tree:
	binomial_tree b_treeb(1500);
	b_treeb.parameters_calculator(ECb_object, Stockb_object);
	b_treeb.price_calculator(ECb_object, Stockb_object, &ECb_object);
	cout << "Binomial Tree: C = $" << b_treeb.get_price() << endl;
Last edited on
I have the following situation. I have 2 classes; call them ClassA and ClassB.

I have another class; call it Class1. Class1 has several methods that use members from either ClassA or ClassB. However, it has a particular method that needs to know what kind of class is being passed into it (for instance, if I pass an object of ClassA into it, then it does something, but if I pass an object of ClassB into it, then it does something else). Currently, Class1 is blind to the type of class that is being passed into its methods. (I achieved this by having ClassA and ClassB being children classes of a single parent class, and passing in a reference to the parent class inside the methods in Class1.) I need to keep Class1 blind to the type of class that is being passed into its methods, yet I also need to determine the class that is being passed into it for one of its methods. Is this possible to do? If so, how do I go about doing this?


1
2
3
4

class1_method(ClassA variable) {do something1}
class1_method(ClassB variable) {do something2}
That is not a valid solution to his problem.

What do you need to have happen? You should 'tell' the class that you get to do their thing and, because THEY know what they are, they can do different things. An outside view need not know what something is.
Thank you for all of your responses.
Topic archived. No new replies allowed.