Overload virtual member function in polymorphism?

I defined a virtual class and three other classes based on it


I want to use them like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {
	Dirichlet_t D;
	Neumann_t N;
	Cauchy_t C;

	PDEBoundary_t * B1=& D;
	PDEBoundary_t * B2=& N;
	PDEBoundary_t * B3=& C;

	B1->setValue(1); //call D.setValue()
	B2->setValue(2); //call N.setValue()
	B3->setValue(3, 3); //vall C.setValue()

	return 0;
}


to realize this, I defined the class like this:

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
#include <cmath>

using namespace std;


typedef double numeric_t;
typedef   long   index_t;

class PDEBoundary_t {
public:
	virtual void setValue(numeric_t) =0;
	virtual void setValue(numeric_t, numeric_t)=0;
	virtual numeric_t value() =0;
	virtual numeric_t value(numeric_t, numeric_t, bool)=0;
	virtual numeric_t value(numeric_t, bool)=0;


    virtual ~PDEBoundary_t();
};

class Dirichlet_t:public PDEBoundary_t {
	numeric_t val;
public:
	Dirichlet_t() {val=0;}
	Dirichlet_t(numeric_t v) {val=v;}
	inline void setValue(numeric_t v) {val=v;}
	inline numeric_t value() {return val;}
};

class Neumann_t:public PDEBoundary_t {
	numeric_t der;
public:
	Neumann_t() {der=0;}
	Neumann_t(numeric_t v) {der=v;}
	inline void setValue(numeric_t v) {der=v;}
	inline numeric_t value(numeric_t delta, numeric_t theOther, bool first) {
		return first?der*delta+theOther:theOther-der*delta;}
};

class Cauchy_t:public PDEBoundary_t {
	numeric_t val, der;
public:
	Cauchy_t() {
		val=0;
		der=0;
	}
	Cauchy_t(numeric_t v, numeric_t d) {
		val=v;
		der=d;
	}
	inline void setValue(numeric_t v, numeric_t d) {val=v; der=d;}
	inline numeric_t value(numeric_t delta, bool first) {
		return first?der*delta+val:val-der*delta;}
};

but I got two major errors
1: "object f abstract type is not allowed" error.-----why not?
2: "the derived class must implement the inherited pure virtual method"-----Did't I?
Last edited on
PDEBoundary_t has 5 virtual functions. For any derived class to be instantiated they must implement ALL 5 of them:

None of your derived classes do this.

Dirichlet_t is missing:
1
2
3
virtual void setValue(numeric_t, numeric_t)=0;
virtual numeric_t value(numeric_t, numeric_t, bool)=0;
virtual numeric_t value(numeric_t, bool)=0;



Neumann_t is missing:
1
2
3
virtual void setValue(numeric_t, numeric_t)=0;
virtual numeric_t value() =0;
virtual numeric_t value(numeric_t, bool)=0;


Cauchy_t is missing:
1
2
3
virtual void setValue(numeric_t) =0;
virtual numeric_t value() =0;
virtual numeric_t value(numeric_t, numeric_t, bool)=0;




On a side note... the error message should be telling you exactly which functions each class is missing.
Thanks, Disch!

I just copied all this into Dirichlet_t, Neumann_t and Cauchy_t respectively, it doesn't work, the error message keep the same.

Do I need to give them a real "doing something" definition?

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
class PDEBoundary_t {
public:
	virtual void setValue(numeric_t) =0;
	virtual void setValue(numeric_t, numeric_t)=0;
	virtual numeric_t value() =0;
	virtual numeric_t value(numeric_t, numeric_t, bool)=0;
	virtual numeric_t value(numeric_t, bool)=0;


    virtual ~PDEBoundary_t();
};

class Dirichlet_t:public PDEBoundary_t {
	numeric_t val;
public:
	Dirichlet_t() {val=0;}
	Dirichlet_t(numeric_t v) {val=v;}
	inline void setValue(numeric_t v) {val=v;}
	inline numeric_t value() {return val;}

	virtual void setValue(numeric_t, numeric_t)=0;
	virtual numeric_t value(numeric_t, numeric_t, bool)=0;
	virtual numeric_t value(numeric_t, bool)=0;
};

class Neumann_t:public PDEBoundary_t {
	numeric_t der;
public:
	Neumann_t() {der=0;}
	Neumann_t(numeric_t v) {der=v;}
	inline void setValue(numeric_t v) {der=v;}
	inline numeric_t value(numeric_t delta, numeric_t theOther, bool first) {
		return first?der*delta+theOther:theOther-der*delta;}

	virtual void setValue(numeric_t, numeric_t)=0;
	virtual numeric_t value() =0;
	virtual numeric_t value(numeric_t, bool)=0;
};

class Cauchy_t:public PDEBoundary_t {
	numeric_t val, der;
public:
	Cauchy_t() {
		val=0;
		der=0;
	}
	Cauchy_t(numeric_t v, numeric_t d) {
		val=v;
		der=d;
	}
	inline void setValue(numeric_t v, numeric_t d) {val=v; der=d;}
	inline numeric_t value(numeric_t delta, bool first) {
		return first?der*delta+val:val-der*delta;}

	virtual void setValue(numeric_t) =0;
	virtual numeric_t value() =0;
	virtual numeric_t value(numeric_t, numeric_t, bool)=0;

};
Last edited on
I just copied all this into Dirichlet_t, Neumann_t and Cauchy_t respectively, it doesn't work, the error message keep the same.


No no... you have to give those functions BODIES.


EDIT:

Actually... since each class has a slightly different interface.. you probably should not be using inheritance at all here. The best solution is probably to just get rid of the PDEBoundary_t class entirely.
Last edited on
Thanks, Yeah, I tried it and that's the problem. but you know, I don't have bodies for them. They basically should not be a member of that class.

Well, I can give them some whatever "error message printing" bodies.

But is there any other better way to realize what I want to do? I mean polymorphism in another way?
Last edited on
northfly wrote:
They basically should not be a member of that class.


Which is why you shouldn't be using inheritance.

The whole point of polymorphism is so you can use different classes with the same interface. That way you do not have to write different code to use each class.

Any class derived from PDEBoundary_t should be able to be treated like a PDEBoundary_t. You should not have to know which derived type you are working with in order to use it. If you do, it defeats the entire point of polymorphism.

However... in your class... all 3 have different interfaces... and therefore it does not make any sense to derive them all from a common parent.

Example:

1
2
3
4
5
6
7
8
9
// This function takes an abstract 'PDEBoundary_t' object
//   The whole point of taking an abstract object is so that it will work with
//   ANY AND ALL derived classes

void stuff(PDEBoundary_t& a)
{
    a.setValue(10);
    cout << a.value();
}


Your problem is this function will only work with a Dirichlet_t. It will not work with the other 2 classes. So therefore... since the function will only work with a Dirichlet_t, it makes sense for it to take a Dirichlet_t as a parameter:

1
2
3
4
5
6
7
8
// this makes more sense.  The function will only work
// with a Dirichlet_t... it will not work with any PDEBoundary_t

void stuff(Dirichlet_t& a)  // <-
{
    a.setValue(10);
    cout << a.value();
}



So really... there is no point to PDEBoundary_t here.


northfly wrote:
But is there any other better way to realize what I want to do?


I'm not sure exactly what it is you're trying to do.

Your PDEBoundary_t class appears to be completely useless to me. I would recommend removing it entirely.
Last edited on
ok, now the program become like this:

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <iostream>
#include <fstream>
#include <sstream>

#include <vector>
#include <string>

#include <iomanip>
#include <cstdlib>
#include <cmath>

using namespace std;


typedef double numeric_t;
typedef   long   index_t;

class PDEBoundary_t {
public:
	virtual void setValue(numeric_t) =0;
	virtual void setValue(numeric_t, numeric_t)=0;
	virtual numeric_t value() =0;
	virtual numeric_t value(numeric_t, numeric_t, bool)=0;
	virtual numeric_t value(numeric_t, bool)=0;


    virtual ~PDEBoundary_t();
};

class Dirichlet_t:public PDEBoundary_t {
	numeric_t val;
public:
	Dirichlet_t() {val=0;}
	Dirichlet_t(numeric_t v) {val=v;}
	inline void setValue(numeric_t v) {val=v;}
	inline numeric_t value() {return val;}

	virtual void setValue(numeric_t v1, numeric_t v2) {
		cout<<"stupid!"<<endl;
	}
	virtual numeric_t value(numeric_t v1, numeric_t v2, bool b) {
		cout<<"stupid!"<<endl;

		return 0;
	}
	virtual numeric_t value(numeric_t v, bool b) {
		cout<<"stupid!"<<endl;

		return 0;
	}
};

class Neumann_t:public PDEBoundary_t {
	numeric_t der;
public:
	Neumann_t() {der=0;}
	Neumann_t(numeric_t v) {der=v;}
	inline void setValue(numeric_t v) {der=v;}
	inline numeric_t value(numeric_t delta, numeric_t theOther, bool first) {
		return first?der*delta+theOther:theOther-der*delta;}

	virtual void setValue(numeric_t v1, numeric_t v2) {
		cout<<"stupid!"<<endl;
	}
	virtual numeric_t value() {
		cout<<"stupid!"<<endl;
		return 0;
	}
	virtual numeric_t value(numeric_t v, bool b) {
		cout<<"stupid!"<<endl;
		return 0;
	}
};

class Cauchy_t:public PDEBoundary_t {
	numeric_t val, der;
public:
	Cauchy_t() {
		val=0;
		der=0;
	}
	Cauchy_t(numeric_t v, numeric_t d) {
		val=v;
		der=d;
	}
	inline void setValue(numeric_t v, numeric_t d) {val=v; der=d;}
	inline numeric_t value(numeric_t delta, bool first) {
		return first?der*delta+val:val-der*delta;}

	virtual void setValue(numeric_t v) {
		cout<<"stupid!"<<endl;
	}
	virtual numeric_t value() {
		cout<<"stupid!"<<endl;
		return 0;
	}
	virtual numeric_t value(numeric_t v1, numeric_t v2, bool b) {
		cout<<"stupid!"<<endl;

		return 0;
	}

};

int main() {
	Dirichlet_t D;
	Neumann_t N;
	Cauchy_t C;

	PDEBoundary_t * B1=& D;
	PDEBoundary_t * B2=& N;
	PDEBoundary_t * B3=& C;

	B1->setValue(1);
	B2->setValue(2);
	B3->setValue(3, 3);

	return 0;
}


But this one still get two errors as:
make***[file name]error 1
target 'all' not remade because of errors


what is this?
Last edited on
But this one still get two errors as:
make***[file name]error 1
target 'all' not remade because of errors


Can you post the actual error message? "error 1" doesn't tell me anything.


Also you posted just after I posted my previous reply. Be sure to read it.
Actually... since each class has a slightly different interface.. you probably should not be using inheritance at all here. The best solution is probably to just get rid of the PDEBoundary_t class entirely.

The reason I did this is I actually want to use them in this way.
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
int main() {
    

   enum BoundaryLabel_t {Dirichlet, Neumann, Cauchy};


    BoundaryLabel_t BL;

    cout<<"Please enter Boundary type and their values: "

    cin>>BL;



    switch (BL) {
    case Dirichlet:
          numeric_t v;
          cin>>v;
          PDEBondary_t *B =new Dirichlet_t(v);
         break;
    case Neumann:
          numeric_t v;
          cin>>v;
          PDEBondary_t *B =new Neumann_t(v);
         break;
    case Cauchy:
          numeric_t v1, v2;
          cin>>v1>>v2;
          PDEBondary_t *B =new Cauchy_t(v1, v2);
         break;

    return 0;
}

Last edited on
The reason I did this is I actually want to use them in this way.


But even that code does not make sense.

So you have an abstract 'B' object... but you can't use it without knowing exactly which derived type you have. So why don't you just use the derived type directly?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    switch (BL) {
    case (Dirichlet):{
          numeric_t v;
          cin>>v;
          Dirichlet_t B(v); // no value in polymorphism here
         }break;
    case (Neumann):{
          numeric_t v;
          cin>>v;
          Neumann_t B(v); // or here
         }break;
    case (Cauchy):{
          numeric_t v1, v2;
          cin>>v1>>v2;
          Cauchy_t B(v1, v2);  // or here
         }break;


See what I mean? What good is having an abstract class if you can't use it abstractly?
Last edited on
See what I mean? What good is having an abstract class if you can't use it abstractly?

Thanks alot! Disch, I got you.

Actually, I want to have a class called block_t, this one should have a member variable PDEBoundary_t,

1
2
3
4
class block_t {
public:
    PDEBoundary_t B;
};


I need this one to be versatile, so it can read in

Dirichlet_t with one value
or
Neumann_t with one value
or
Cauchy_t with two value

How can I implement this?


How can I realize this
Last edited on
The error message just showed up like that, with any other details.

But if I delete the virtual destructor, virtual ~PDEBoundary_t();, then errors disappear and warnings come up:


class "some number code" have virtual method "value" but non-virtual destructor

this message appeared four times, I believe they refers to the four classes
It's very difficult for me to give the best approach without knowing how this is actually going to be used.

The bottom line is that if your classes do not share a common interface, they cannot be used interchangably like you want. So if you want them to be abstracted, you'll have to find a way to make them all work with a common interface.


But again... depending on what these classes are/how they're used... that simply may not be possible.
Thanks Disch! Can anybody give me some hint on how to design this?

what I want:

I want to have a class block_t, this class have a PDEBoundary_t member,

1
2
3
4
class block_t {
public:
    PDEBoundary_t B;
};


after I defined some block_t

block_t blk;

then I can assign different bounday conditions to this blk, and depends on what type it is, it will have to set either one value for Dirichlet_t and Neumann_t, or two values for Cauchy_t.

How can I implement this, I have been thinking about this for a long long time, please help me out. Thank you very much!




Last edited on
You need to think how would the `PDEBoundary_t' object be used.

By instance, it should set the coefficients in a A_{jk} x_k = b_j equation with the finite difference method
Considering a 1D case you can have
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[a, b] Dirichlet::retrieve(){
   a = [1 0];
   b = value;
}

[a, b] Newman1::retrieve(){
   a = [1 -1];
   b = h*value;
}

[a, b] Newman2::retrieve(){
   a = [2 -2];
   b = 2*h*value;
}
So the block would simply call `B->retrieve()' and obtains the coefficients for the matrix and the result vector
Last edited on
Thanks, ne555!
Topic archived. No new replies allowed.