abstract methods, virtual methods

Pages: 123
Now I had an idea. Why we need the base class (abstract class) and all the virtual methods? Ain't it simpler to skip definition of the virtual methods in base class? I can define the methods in derived class. So why do I need the base class (if I omit the fact, that there can be attributes which can hold values shared for all derived classes).

Is the abstract definition needed for example because of we want to use both derived classes (instances) by one set of shared methods, instead of doing two or three sets of separated methods? So all three types (triggers/conditions/effects) can be proceesed with one set of methods?
Last edited on
Now I had an idea. Why we need the base class (abstract class) and all the virtual methods? Ain't it simpler to skip definition of the virtual methods in base class? I can define the methods in derived class. So why do I need the base class (if I omit the fact, that there can be attributes which can hold values shared for all derived classes).

If you define the base class to have a virtual method, and override that method in derived classes, then it allows you to make use of polymorphism.

You can have a base-class pointer, and it can point to an object of any of the derived classes. When you call a method on that pointer, the correct implementation of the method will be called, based on which object the pointer is actually pointing to.

So if you 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
class Base
{
public:
  virtual myMethod() { std::cout << "Base class" << std::endl; }
}

class Derived1 : public Base
{
public:
  virtual  myMethod() { std::cout << "Derived1 class" << std::endl; }
}

class Derived2 : public Base
{
public:
  virtual  myMethod() { std::cout << "Derived2 class" << std::endl; }
}

// ...
void myFunc()
{
  Base aBase;
  Derived1 aDerived1;
  Dervied2 aDerived2;

  Base* ptr = &aBase;
  ptr->myMethod();  // Outputs "Base class"

  ptr = &aDerived1;
  ptr->myMethod();  // Outputs "Derived1 class"

  ptr = &aDerived2;
  ptr->myMethod();  // Outputs "Derived2 class"
}


Even though ptr is a pointer to Base, the correct method is called based on what it points to.

If the Base class didn't have a virtual myMethod() in its interface, I couldn't do this.
Even though ptr is a pointer to Base, the correct method is called based on what it points to.


I see but you must change the pointer every time you want to call method from different instance. The only advantage here is that you have only one pointer which is only one declaration of pointer. Edit: and another advantage I see now is that if you want call these methods from superior function, you can do it by one line; just calling ptr->myMethod... but there must be some argument in the superior function, something like superiorCall(type) and some mechanism which will control which method to use. Which class type to call ....
This is on page 2:
1
2
3
4
ECBase& source =
	(data->type == CONDITION) ?
	static_cast<ECBase&>(t->conds[data->index]) :
	t->effects[data->index];

The first is type Condition the second is type Effect, and you can both pass to one source to call them later with source.toBuffer(data);
.


But I could discard the virtual keywords in your code and then call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void myFunc()
{
  Base aBase;
  Derived1 aDerived1;
  Derived2 aDerived2;

  Base* ptr = &aBase;
  Derived1* ptr1 = &aDerived1;
  Derived2* ptr2 = &aDerived2;

  ptr->myMethod();  // Outputs "Base class"
  ptr1->myMethod();  // Outputs "Derived1 class"
  ptr2->myMethod();  // Outputs "Derived2 class"
}

So this is simple too, and I don't need to use later building. It also looks more clear and you know that these methods are different even that they have same name because they are in different classes.

Another note:
I think real advantage of the polymorphism should be in the fact that if you pass different types (in my example I use three types: TRIGGER, EFFECT, CONDITION) so you would save some coding because you could use one method or one set of methods to manipulate different types... but I am still not sure with it. Maybe this would be simple changeable with templates. They also enables you to define methods with same name, but using different types. I mean template specialisation. But I think this would mean different concept / design. Because that things which are now devided to 3 files - three different classes would have to be in one file as one big template - I think it would be very unclear and hard to type such big template. Because as far as I understand templates, they should simplify the programming, not to make them more complicated :-)
Last edited on
h4ever wrote:
I think SVector is author's own designed vector to keep and manipulate objects.

http://paste.ofcode.org/Uh6BYsJ2NyFXSvpeqYnrcv

I used std::vector instead.

SVector has method at. std::vector has method at. They are different, so it is no wonder that your code breaks when you replace the container type.
I still don't understand. I did exactly how they have in the project. Except using SVector.

1
2
3
4
5
6
7
8
9
10
11
12
class ItemData
{
public:
inline virtual Trigger *GetTrigger()
{ return scen.triggers.at(index); }
};

class Scenario
{
public:
	SVector <Trigger> triggers;
};


You see there are different types. It does not matter if .at is there or not.

1
2
3
inline virtual Trigger *GetTrigger()
	{ return scenario.triggers; // will produce similar error
	}


abstract_method_test.h(56): error C2440: 'return' : cannot convert from 'std::vector<_Ty>' to 'Trigger *'
with
[
_Ty=Trigger
]
It does not matter if .at is there or not.

Doesn't? What does the member function at() of these two container objects do?
returns reference to element in vector. But you must call it before it can return it. It is not part of constructor.
Last edited on
No. std::vector::at does return a reference, but SVector::at returns a pointer.

What do constructors have to do with element access?
I see but you must change the pointer every time you want to call method from different instance. The only advantage here is that you have only one pointer which is only one declaration of pointer.

I was posting a simple example of code to show you how polymorphism works. The benefit of it is that when when you want to write code that calls a method on the pointer, you don't need to write code to deal with each specific class in the heirarchy, you can just call the method on the pointer, and trust that the correct implementation of that method will be called.

That's extremely powerful, and helps you simplify code a great deal.

I'm afraid I can't follow your English in most of the rest of your post, so I can't respond to your points. It sounds like you probably understand the concept of polymorphism, but want to dismiss it in favour of explicitly writing code for every different type. That's much more time-consuming, and harder to maintain.

Templates are a good solution if you want to apply the same code to multiple different types. But that's not always the case.
keskiverto:
I think we have some problems in terms. Check code:

1
2
3
4
template <class _AC> class SVector
{
// contains this line:
	_AC* at(size_t offset)

pointers (*) and references (&). Confirmed. std::vector::at returns reference or const reference.

Private method of of SVector, which is called by SVector(const SVector &source) constructor:
1
2
3
4
5
6
7
8
9
10
	_AC *copy(_AC *dest, const _AC *source, int count)
	{
		_AC *next = dest;

		while (count--)
			new (next++) _AC(*source++);

		return next;
	}


the copy() gets reference to destination element and saves it in member "next". It's not clear to me the way he allocated memory. Now I cannot access the page with manual for "new" but msdn:
new [placement] new-type-name [new-initializer]
So he can create more pointers not just one. Every pointer points to one object. Probably if he "copies" efffect or condition, he makes just one "copy", if he copies trigger, he "copies" 1 trigger, 0 or more conditions and 0 or more effects.
You were calling at() in
1
2
3
4
Trigger * ItemData::GetTrigger()
{
  return triggers.at(index);
}

And you did not comprehend why it was fine to have SVector<Trigger> triggers, but having std::vector<Trigger> triggers creates a "cannot implicitly convert reference to pointer" error. Do you now know better?


Frankly, I don't give a damn about the SVector::copy, but it does not "create pointers".
What do constructors have to do with element access?

I answered you that Constructor calls copy method. But I was wrong:

std::vector<Trigger> triggers
It calls different constructor. I really don't follow where is the pointer declared, the result type...

Trigger * ItemData::GetTrigger()
{
return triggers.at(index);
}

Do you want to say, this is what declares the pointer type *? It looks so. There is not declaration in the SVector template...
I answered you that Constructor calls copy method.

Totally irrelevant. You had a problem when trying to access from a container with container's method at. At that point the container either has an already constructed element at index, or there is no element. No construction, no copy.


The function ItemData::GetTrigger does declare that it returns a pointer to object of type Trigger. (Although, a pointer can be null, i.e. no object.) In practice, ItemData::GetTrigger returns whatever triggers.at(index) does return.

When triggers is SVector<Trigger>, at returns a pointer to object of type Trigger. That pointer can be directly returned by ItemData::GetTrigger.

When triggers is std::vector<Trigger>, at returns a reference to object of type Trigger. A reference cannot be implicitly converted into a pointer, and therefore you do have a syntax error.
Ok, thanks for explanation. I was looking for some result declaration and that type the function returns but, I did not noticed the star in header which is very important.

Mostlikely, I will have a small break of C++. Thanks.
Topic archived. No new replies allowed.
Pages: 123