abstract methods, virtual methods

Pages: 123
So when you said clear virtual methods you mean abstract method.

You want to say that abstract class (abstract base) cannot be copied. It is expected that I will copy the derived class.

Also I did not know that abstract method cannot have implementation!

Quite good explanation from you, thanks!
So this piece of code calls tobuffer on derived class.

1
2
3
4
5
6
7
8
ECBase& source =
	(data->type == CONDITION) ?
	static_cast<ECBase&>(t->conds[data->index]) :
	t->effects[data->index];

// get the size by doing a dummy write
NullBuffer nullbuff;
source.tobuffer(nullbuff);


There is tobuffer defined in Trigger class. static_cast declares that, variable source refers to instance of Trigger class. However why there must be static_cast<ECBase&> and not static_cast<Trigger&>. Probably because Trigger does not inherit ECBase? But if Triggger is not derived class how can they "overtype" or "retype" (idk correct term) the Trigger class to ECBase?
Last edited on
I did not know that abstract method cannot have implementation!

Not quite. I had a bit biased comment there.
Pure virtual function can have an implementation in the same class.
Pure virtual function has to have an implementation in derived class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Foo
{
  virtual void foo() = 0;
};

virtual void Foo::foo() { std::cout << 7; }

struct Bar : public Foo
{
  virtual void foo() { Foo::foo(); std::cout << '\n'; }
};

void main()
{
  Bar b;
  Foo * p = &b;
  p->foo();  // calls Bar::foo(), which uses Foo::foo()
}

You cannot have objects of type plain Foo, because Foo is abstract.
You can have type Bar objects, which include type Foo component.

Foo provides a default implementation for foo(), but it is up to the Bar whether it is used in any way.

So this piece of code calls tobuffer on derived class.

Only if the real type of the object is a class derived from ECBase, ECBase introduces tobuffer() as virtual, and a derived class provides tobuffer().

if Triggger is not derived class how can they "overtype" or "retype" (idk correct term) the Trigger class to ECBase?

They should not. If you have put a rattlesnake into an empty bag and then you put your hand into the same bag expecting to find apples, you are likely to be surprised.

However, Trigger has nothing to do with that code. You have t->conds and you have told that std::vector<Condition> conds;. In other words, there is an attempt to use a memory location that contains a Condition object like it had an ECBase object.

You should pay much more attention to the details.
This makes me confused :-( You say:
"Pure virtual function can have an implementation in the same class." and "Foo provides a default implementation for foo(), "

But I don't see that foo implementation in your code, only =0. Do you take the zero as implementation? If you skipped the implementation then I would expect code like

1
2
virtual foo()=0;
virtual foo(int param){privateMember=param;}
That would be the missing implementation of the abstract class...

BTW: Trigger class contains two members, effects and conds. They both stores these effects and condition of type vector.
And I did not found where t is defined, but in ItemData::GetName there is Trigger *t = scen.triggers.at(index); ... so this leads me to Scenario class. There I found Trigger *t = triggers.first(); And now finally I have found Scenario::Triggers declaration:
SVector <Trigger> triggers;

So there is Scenario::Triggers::Effects and Scenario::Triggers::Conds (if I am right in my research :-)
Last edited on
But I don't see that foo implementation

Line 6.
So you made the abstract method declaration externally, but you did not made the declaration in derived class. But you said "Pure virtual function has to have an implementation in derived class."

From the above I see that both types of methods need to have declaration, either in base class or in the derived class, difference is, that the abstract method can not have the declaration in the base class, so it is made externally.

And then there is the rule, that the abstract class cannot be initiated (instantiated)

Another rule, that while normal method can be called directly on derived class derivedClassInstance.normalMethod() ..., on pointer of type of base class it will be called on base class ...
1
2
Base * p = &derivedClassInstance;
p->normalMethod(); // calls Base::normalMethod() 


And last rule is that the abstract method can be called only on the reference
p->abstractMethod(); //calls DerivedClass::abstractMethod()
Last edited on
No.

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
struct Foo
{
  virtual void foo() = 0; // declaration
};

struct Bar : public Foo
{
  virtual void foo(); // declaration

  virtual int bar() const // both declaration and definition
  {
    return 42;
  }
};

// definition / implementation
virtual void Bar::foo()
{
  Foo::foo();
  std::cout << '\n';
}

// definition / implementation
virtual void Foo::foo()
{
  std::cout << 7;
}

I would like to try to write the code how it works on my own, but respecting the way how it is in the project.

Header:
http://paste.ofcode.org/Kc96cHbX6abTMwpSES6UNb
(here I have error:
abstract_method_test.h(8): error C2236: unexpected 'class' 'Effect'. Did you forget a ';'?
abstract_method_test\abstract_method_test.h(8): error C2143: syntax error : missing ';' before ':'

Cpp:
http://paste.ofcode.org/k4ZYuUPjDKDYhYnPv3Xwdw

Can you help to remove the errors?
Your compiler gives a good hint.

If that is not enough, seek "end of compound statement" from http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Companion/cxx_crib/class.html
I was convinced there should not be ;. I never noticed it is there }; !
Last edited on
http://paste.ofcode.org/39TPF6jSTLuP2nq4MbGy3He
http://paste.ofcode.org/9DQTMM2hAPMeWvQ3yi8nTa

And this error?
abstract_method_test.cpp(21): error C2597: illegal reference to non-static member 'Scenario::triggers'
Last edited on
triggers is a member of class Scenario. Each Scenario object has one triggers member object. Whose triggers are you trying to pass to the function?
I was wrong. There should be the scen instance:
test.justtest(scen.triggers,data);
but now there is error:

abstract_method_test.cpp(21): error C2664: 'Test::justtest' : cannot convert parameter 1 from 'std::vector<_Ty>' to 'Trigger *'
with
[
_Ty=Trigger
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

But
test.justtest(scen::triggers,data);
prints
abstract_method_test.cpp(21): error C2510: 'scen' : left of '::' must be a class/struct/union
abstract_method_test.cpp(21): error C2065: 'triggers' : undeclared identifier
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
Last edited on
There is nothing surprising in that error. Explain us why the C2664 shows up. Doing so should help you to learn a bit.
idk why thats why I ask
Think.
What is the type of scen.triggers?
What is the type of the first parameter of function test.justtest?
I tried to make it similar in the way how it is in the project. They have:

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
Trigger *c_trig;

bool Update_ctrig(HWND treeview)
{
	HTREEITEM sel;
	class ItemData *data;
	c_trig = NULL;
         // .. bla bla  ..
	c_trig = data->GetTrigger();

	return (c_trig != NULL);
}

INT_PTR Handle_WM_COMMAND(HWND dialog, WORD code, WORD id, HWND)
{
	HWND treeview = GetDlgItem(dialog, IDC_T_TREE);	//all use this

	switch (code)
	{
	case BN_CLICKED:
	case 1:
		switch (id)
		{
		case ID_EDIT_COPY:
			SAFECHECK();
			if (GetFocus() == treeview)
			{
			Trig_ToClipboard(dialog, c_trig, (class ItemData*)data);
			}
		// ... bla bla ...
		break;
		// ... bla bla ...
	break;
	}
	return 0;
}

class ItemData
{
public:
       // ... bla bla ...
	inline virtual Trigger *GetTrigger()
	{ return scen.triggers.at(index); }

};

void Trig_ToClipboard(HWND dialog, Trigger *t, class ItemData *data)
{
         // ... bla bla ...
	if (data->type == TRIGGER)
	{
                 // ... bla bla ...
	}
	else if (data->type == CONDITION || data->type == EFFECT)
	{		
		ECBase& source =
			(data->type == CONDITION) ?
			static_cast<ECBase&>(t->conds[data->index]) :
			t->effects[data->index];
		NullBuffer nullbuff;
		source.tobuffer(nullbuff);
                 // ... bla bla ...
		source.tobuffer(b);
  }
}


So there is the function call Trig_ToClipboard(dialog, c_trig, (class ItemData*)data);
c_trig is type Trigger. BTW: another thing I dont understand in this place is why (class ItemData*) ... why not just (ItemData*)

Note: the ItemData is base class for class EffectItemData and ConditionItemData, they should change the effect and condition data...

I am not going to recreate all that stuff again, I just want to try to make the classes work in the basic idea/principle. It would be simpler to me to have that code simplified in very simple example, so I can see how it all works.
Last edited on
Change made in .h
http://paste.ofcode.org/ZvS8gCeHAwd4srBN9Na3T8

1
2
3
4
5
6
7
class ItemData
{
public:
	unsigned index;	//to scen.triggers
	inline virtual Trigger *GetTrigger()
	{ return scenario.triggers.at(index); }
};


Looks like this error is obvious, but in the original project the code above yields no error!
abstract_method_test.h(55): error C2440: 'return' : cannot convert from 'Trigger' to 'Trigger *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

Last edited on
h4ever wrote:
SVector <Trigger> triggers;

Who is SVector?
I think SVector is author's own designed vector to keep and manipulate objects.

http://paste.ofcode.org/Uh6BYsJ2NyFXSvpeqYnrcv

I used std::vector instead.
Pages: 123