Assigment operator and container of base type

A

Adrian

Below is an example of the problem I am having. I don't understand how
I can get the compiler to see deriv &operator=(const T &rhs).

I am sure this is a common problem - any suggestions?


#include <iostream>
#include <vector>

struct base
{
virtual ~base()=0 {};
};

template<class T>
struct deriv : public base
{
deriv(): data_(0) {};
deriv(const T &data): data_(data) {};
deriv &operator=(const T &rhs) { data_=rhs; return (*this); }
deriv &operator=(const deriv &rhs)
{ data_=rhs.data_; return (*this); }
T data_;
};

struct container
{
base &operator[](int i) { return *(data_); };
std::vector<base *> data_;
};

void fill_cont(container &data);

int main(int argc, char *argv[])
{
container data;
fill_cont(data);

std::cout << "data[0]=" << typeid(data[0]).name() << std::endl;
// output: data[0]=struct deriv<int>
data[0]=12445;

std::cout << "data[1]=" << typeid(data[1]).name() << std::endl;
// output: data[1]=struct deriv<double>
data[1]=4.5667;

std::cout << "data[2]=" << typeid(data[2]).name() << std::endl;
// output: data[2]=struct deriv<char *>
data[2]="test";

return 0;
}

void fill_cont(container &data)
{
data.data_.push_back(new deriv<int>());
data.data_.push_back(new deriv<double>());
data.data_.push_back(new deriv<char *>());
}
 
O

Ondra Holub

Adrian napsal:
Below is an example of the problem I am having. I don't understand how
I can get the compiler to see deriv &operator=(const T &rhs).

I am sure this is a common problem - any suggestions?


#include <iostream>
#include <vector>

struct base
{
virtual ~base()=0 {};
};

template<class T>
struct deriv : public base
{
deriv(): data_(0) {};
deriv(const T &data): data_(data) {};
deriv &operator=(const T &rhs) { data_=rhs; return (*this); }
deriv &operator=(const deriv &rhs)
{ data_=rhs.data_; return (*this); }
T data_;
};

struct container
{
base &operator[](int i) { return *(data_); };
std::vector<base *> data_;
};

void fill_cont(container &data);

int main(int argc, char *argv[])
{
container data;
fill_cont(data);

std::cout << "data[0]=" << typeid(data[0]).name() << std::endl;
// output: data[0]=struct deriv<int>
data[0]=12445;

std::cout << "data[1]=" << typeid(data[1]).name() << std::endl;
// output: data[1]=struct deriv<double>
data[1]=4.5667;

std::cout << "data[2]=" << typeid(data[2]).name() << std::endl;
// output: data[2]=struct deriv<char *>
data[2]="test";

return 0;
}

void fill_cont(container &data)
{
data.data_.push_back(new deriv<int>());
data.data_.push_back(new deriv<double>());
data.data_.push_back(new deriv<char *>());
}


The code is quite long, but for me is strange for example pure virtual
destructor in base class.
 
O

Ondra Holub

Adrian napsal:
Below is an example of the problem I am having. I don't understand how
I can get the compiler to see deriv &operator=(const T &rhs).

I am sure this is a common problem - any suggestions?


#include <iostream>
#include <vector>

struct base
{
virtual ~base()=0 {};
};

template<class T>
struct deriv : public base
{
deriv(): data_(0) {};
deriv(const T &data): data_(data) {};
deriv &operator=(const T &rhs) { data_=rhs; return (*this); }
deriv &operator=(const deriv &rhs)
{ data_=rhs.data_; return (*this); }
T data_;
};

struct container
{
base &operator[](int i) { return *(data_); };
std::vector<base *> data_;
};

void fill_cont(container &data);

int main(int argc, char *argv[])
{
container data;
fill_cont(data);

std::cout << "data[0]=" << typeid(data[0]).name() << std::endl;
// output: data[0]=struct deriv<int>
data[0]=12445;

std::cout << "data[1]=" << typeid(data[1]).name() << std::endl;
// output: data[1]=struct deriv<double>
data[1]=4.5667;

std::cout << "data[2]=" << typeid(data[2]).name() << std::endl;
// output: data[2]=struct deriv<char *>
data[2]="test";

return 0;
}

void fill_cont(container &data)
{
data.data_.push_back(new deriv<int>());
data.data_.push_back(new deriv<double>());
data.data_.push_back(new deriv<char *>());
}



--

Adrian

Think you know a language? Post to comp.lang... and find out!


In container::eek:perator[] you are returning reference to base. But there
is no assignment operator in class 'base', so compiler cannot see it.
 
R

Robert Bauck Hamar

Adrian said:
Below is an example of the problem I am having. I don't understand how
I can get the compiler to see deriv &operator=(const T &rhs).

The problem is that this function doesn't exist in base, which is the static
type. The compiler will only search the object's static type.
I am sure this is a common problem - any suggestions?

Surely. You can cast to whatever type you really have:

dynamic_cast<deriv<int>&>(data[0]) = 12445;

Another "solution" follows.
#include <iostream>
#include <vector>

struct base
{

template said:
virtual ~base()=0 {};

of course this don't work, but your compiler will tell you that.
};

template<class T>
struct deriv : public base
{
deriv(): data_(0) {};
deriv(const T &data): data_(data) {};
deriv &operator=(const T &rhs) { data_=rhs; return (*this); }
deriv &operator=(const deriv &rhs)
{ data_=rhs.data_; return (*this); }
T data_;
};

template <class T>
base& base::eek:perator=(const T& rhs)
{
struct container
{
base &operator[](int i) { return *(data_); };
std::vector<base *> data_;
};

void fill_cont(container &data);

int main(int argc, char *argv[])
{
container data;
fill_cont(data);

std::cout << "data[0]=" << typeid(data[0]).name() << std::endl;
// output: data[0]=struct deriv<int>
data[0]=12445;

std::cout << "data[1]=" << typeid(data[1]).name() << std::endl;
// output: data[1]=struct deriv<double>
data[1]=4.5667;

std::cout << "data[2]=" << typeid(data[2]).name() << std::endl;
// output: data[2]=struct deriv<char *>
data[2]="test";


Of course "test" has type const char[5], not char*, so this will not work.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Below is an example of the problem I am having. I don't understand how
I can get the compiler to see deriv &operator=(const T &rhs).

I am sure this is a common problem - any suggestions?


#include <iostream>
#include <vector>

struct base
{
virtual ~base()=0 {};
};

template<class T>
struct deriv : public base
{
deriv(): data_(0) {};
deriv(const T &data): data_(data) {};
deriv &operator=(const T &rhs) { data_=rhs; return (*this); }
deriv &operator=(const deriv &rhs)
{ data_=rhs.data_; return (*this); }
T data_;
};

struct container
{
base &operator[](int i) { return *(data_); };
std::vector<base *> data_;
};

void fill_cont(container &data);

int main(int argc, char *argv[])
{
container data;
fill_cont(data);

std::cout << "data[0]=" << typeid(data[0]).name() << std::endl;
// output: data[0]=struct deriv<int>
data[0]=12445;

std::cout << "data[1]=" << typeid(data[1]).name() << std::endl;
// output: data[1]=struct deriv<double>
data[1]=4.5667;

std::cout << "data[2]=" << typeid(data[2]).name() << std::endl;
// output: data[2]=struct deriv<char *>
data[2]="test";

return 0;
}

void fill_cont(container &data)
{
data.data_.push_back(new deriv<int>());
data.data_.push_back(new deriv<double>());
data.data_.push_back(new deriv<char *>());
}


I'm quite sure you can't do that. Besides from what Ondra Holub has said
what you are trying to do is to create a heterogeneous container, which
I'm quite sure you can't do. At least not like that, you might succeed
if you first find out what kind of deriv it is and cast it to that type.
But then there would not be much of a point, would it?
 
A

Adrian

Ondra said:
In container::eek:perator[] you are returning reference to base. But there
is no assignment operator in class 'base', so compiler cannot see it.

Should be. The compiler should generate one by default.
 
A

Adrian

Ondra said:
The code is quite long, but for me is strange for example pure virtual
destructor in base class.
This is a useful trick for insuring that the class is abstract.
 
A

Adrian

Robert said:
Adrian wrote:
The problem is that this function doesn't exist in base, which is
the static
type. The compiler will only search the object's static type.
I am sure this is a common problem - any suggestions?

Surely. You can cast to whatever type you really have:

dynamic_cast<deriv<int>&>(data[0]) = 12445;

Another "solution" follows.
#include <iostream>
#include <vector>

struct base
{

template said:
virtual ~base()=0 {};

of course this don't work, but your compiler will tell you that.
What wont work. Nothing wrong with a virtual destructor?

template <class T>
base& base::eek:perator=(const T& rhs)
{
return dynamic_cast<deriv<T>&>(*this) = rhs;
}
Perfect. I didnt try that. I assumed the compiler would never be able
to deduce T.

Thanks for that.
Of course "test" has type const char[5], not char*, so this will not work.
Was just throwing things into the example :)
 
R

Robert Bauck Hamar

Adrian said:
Robert said:
Adrian wrote:
The problem is that this function doesn't exist in base, which is
the static
type. The compiler will only search the object's static type.
I am sure this is a common problem - any suggestions?

Surely. You can cast to whatever type you really have:

dynamic_cast<deriv<int>&>(data[0]) = 12445;

Another "solution" follows.
#include <iostream>
#include <vector>

struct base
{

template said:
virtual ~base()=0 {};

of course this don't work, but your compiler will tell you that.
What wont work. Nothing wrong with a virtual destructor?

The dtor _should_, of course, be virtual. But the above line is a syntax
error. You _can_ do:

class foo {
virtual ~foo() = 0;
};

foo::~foo() {}

but not

class foo {
virtual ~foo() = 0 {}
};
 
A

Adrian

Robert said:
The dtor _should_, of course, be virtual. But the above line is a syntax
error. You _can_ do:

class foo {
virtual ~foo() = 0;
};

foo::~foo() {}

but not

class foo {
virtual ~foo() = 0 {}
};

Gotya. Actually the compiler allows it. I hate it when they dont
follow standards, makes porting a nightmare.

Just found it in the standard. 10.4.2. Makes sense
 
R

Robert Bauck Hamar

Adrian said:
Ondra said:
In container::eek:perator[] you are returning reference to base. But there
is no assignment operator in class 'base', so compiler cannot see it.

Should be. The compiler should generate one by default.

Surely. base& base::eek:perator=(const base&) is declared by default. Remarks:

1. It does not match the signature of deriv<T>& deriv<T>::eek:perator=(const
T&)
2. It is not virtual.

1 Means that when the comiler searches base (static type of lhs in
assignment) for operator=, it cannot see any operator= taking a T, even
though the dynamic type of lhs has one.

2 Means that even if the signatures had matched, the compiler would
statically link to base::eek:perator=. Example of latter:

#include <iostream>

using namespace std;

struct foo {
virtual foo& operator =(const foo&) {
cout << "foo\n";
return *this;
}
};

struct bar : foo {
bar& operator=(const foo&) {
cout << "bar\n";
return *this;
}
};

int main() {
foo f;
bar b;

foo & fb = b;

f = f;
b = b;
fb = b;
}

Delete the virtual kw in foo, and see how output changes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,078
Latest member
MakersCBDBlood

Latest Threads

Top