Public Group

Problem with virtual function

This topic is 2622 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi guys,

Let me post the code first :
[source]

#include <windows.h>
#include <iostream>
#include <vector>

class class1
{
public:
class1(){}

void VoegToe(const class1& t) { h.push_back(t); }
void PrintAlles(){
for(DWORD u=0;u<h.size();u++){
std::cout << "object : " << u << " waarde = ";
h.GetWaarde();
}
}

virtual void GetWaarde() { std::cout << "1" << std::endl; }

private:

std::vector<class1> h;

};

class class2 : public class1
{
public:
class2() {
waarde = 0;
}

void Init(int w, class1& hoof) {
waarde = w;
hoof.VoegToe(*this);
}

void GetWaarde() { std::cout << waarde << std::endl; }

private:
int waarde;

};

int main()
{
class1 test1;
class2 test2;

test2.Init(5, test1);
test1.PrintAlles();

system("pause");
return 0;
}

[/source]

The problem is that it prints 1 instead of 5,
and i cant figure out why it is not overriding the
[source] virtual void GetWaarde() { std::cout << "1" << std::endl; } [/source]
in the base class.

Share on other sites
You've sliced class2 by copying it into a class1 in the vector.

I presume this wasn't your intention as now you're holding a class1 not a class2 which will give you only the base classes methods.

Jans.

Share on other sites

You've sliced class2 by copying it into a class1 in the vector.

I presume this wasn't your intention as now you're holding a class1 not a class2 which will give you only the base classes methods.

Jans.

Yea, i want to hold a class 2 into the vector not a class 1,
but how do i do this without a forward class declaration?
Because when i want to use it class 1 and class 2 are in 2 separate headers,
and class 2 will include class 1 so a forward declaration wont work then.
Or am i wrong?

Share on other sites
To avoid slicing, you must store some kind of reference, not a value. A typical solution is to store (smart) pointers, such as std::vector<std::shared_ptr<Example> >. Another option is to use a smart container, like boost::ptr_vector<Example>.

Share on other sites
Thanks i got it working now with this code :
[source]

#include <windows.h>
#include <iostream>
#include <vector>
#include <boost\ptr_container\ptr_container.hpp>

class class1
{
public:
class1(){}

void VoegToe(class1& t) { h.push_back(dynamic_cast<class1*>(&t)); }
void PrintAlles(){
for(DWORD u=0;u<h.size();u++){
std::cout << "object : " << u << " waarde = ";
h.GetWaarde();
}
}

virtual void GetWaarde() { std::cout << "1" << std::endl; }

private:

boost::ptr_vector<class1> h;

};

class class2 : public class1
{
public:
class2() {
waarde = 0;
}

void Init(int w, class1& hoof) {
waarde = w;
hoof.VoegToe(*this);
}

void GetWaarde() { std::cout << waarde << std::endl; }

private:
int waarde;

};

int main()
{
class1 test1;
class2 test2;

test2.Init(5, test1);
test1.PrintAlles();

system("pause");
return 0;
}
[/source]

But i have 2 questions left :
1. I use a dynamic cast to cast to a pointer, i read somewhere that casts are very expensive.
Is there any other way to do it without a cast?

2. When i exit the program is crashes with a debug assertion failed.
Expression : vector iterators incompatible.
Is this because it cant delete the pointer or something?

Share on other sites

1. I use a dynamic cast to cast to a pointer, i read somewhere that casts are very expensive.
Is there any other way to do it without a cast?
[/quote]
In this case, you don't need a cast here - you are taking the address of a class1 reference, which yields a pointer-to-class1. In general, you do not need a cast to point a base pointer at an address of a derived instance.

Dynamic casts can be expensive. Unfortunately, doing any runtime logic can be expensive. You must first profile and determine whether you've created a bottleneck. If so, you must design and implement a suitable replacement. Finally, you must profile again to ensure you've had a positive impact.

2. When i exit the program is crashes with a debug assertion failed.
Expression : vector iterators incompatible.
Is this because it cant delete the pointer or something?
[/quote]
It is because you place a pointer to an automatically allocated object in a container that imposes ownership semantics. Essentially, boost::ptr_vector<> expects to be able to call delete on the pointer you give it.

If your pointers do in fact outlive the container, then you could store raw pointers to them safely (for a given definition of "safely").

Otherwise here are a few options off the top of my head:

• Allocate the pointer using new, pass as a raw pointer (dangerous)
• Allocate the pointer using new or std::make_shared(), store in std::shared_ptr<>, container is of type std::vector<std::shared_ptr<> >
• Retain current interface, but use a virtual clone() member function to copy the object into the container.

Share on other sites
Oke i did go with the second option :
[source]

#include <windows.h>
#include <iostream>
#include <vector>
#include <memory>

class class1
{
public:
class1(){}

void VoegToe(std::shared_ptr<class1> t) { h.push_back(t); }
void PrintAlles(){
for(DWORD u=0;u<h.size();u++){
std::cout << "object : " << u << " waarde = ";
h->GetWaarde();
}
}

virtual void GetWaarde() { std::cout << "1" << std::endl; }

private:

std::vector<std::shared_ptr<class1>> h;

};

class class2 : public class1
{
public:
class2() {
waarde = 0;
}

void Init(int w, class1& hoof) {
waarde = w;
hoof.VoegToe(std::shared_ptr<class1>(std::make_shared<class1>(*this)));
}

void GetWaarde() { std::cout << waarde << std::endl; }

private:
int waarde;

};

int main()
{
class1 test1;
class2 test2;

test2.Init(5, test1);
test1.PrintAlles();

system("pause");
return 0;
}
[/source]

But it seems the object get sliced again?
Because the output is 1 instead of 5.

Thanks for all the help already : )

Share on other sites
Your call to make_shared() is slicing the object again.

Something like this:
 #include <windows.h> #include <iostream> #include <vector> #include <memory> class class1 { public: class1(){} void VoegToe(std::shared_ptr<class1> t) { h.push_back(t); } void PrintAlles() { for(DWORD u = 0 ; u < h.size() ; u++){ std::cout << "object : " << u << " waarde = "; h->GetWaarde(); } } virtual void GetWaarde() { std::cout << "1" << std::endl; } private: std::vector<std::shared_ptr<class1>> h; }; class class2 : public class1 { public: class2() { waarde = 0; } void Init(int w) { waarde = w; } void GetWaarde() { std::cout << waarde << std::endl; } private: int waarde; }; int main() { class1 test1; std::shared_ptr<class2> test2 = std::make_shared<class2>(); test2->Init(5); test1.VoegToe(test2); test1.PrintAlles(); system("pause"); return 0; } 
Getting a shared_ptr<> to "this" is tricky. There is a helper class, enable_shared_from_this(), but I think the above solution is better.

Share on other sites
Oke, thanks for all your help : )

1. 1
2. 2
Rutin
20
3. 3
khawk
16
4. 4
A4L
14
5. 5

• 11
• 16
• 26
• 10
• 11
• Forum Statistics

• Total Topics
633755
• Total Posts
3013706
×