initializing a class using upcasted object

M

mati

Hi

Here is the code:

class Base {
public:
Base() {...}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
public:
Der():Base() {...}
~Der() {...}
void foo() const {...}
};

There are several Der.. classes, and the problem is that I want to make
some X class, that will have a handle to the Base, in order to use
polymorphism.
Initialization of X objects will determine which actual object in the
Base's hierarchy will be used (Der1 or Der2 or ..), but I have no idea
how to do that in "nice" way.

If I use references as the handle, I end with something like this:

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {...}
~X() {...}
complicated_function_that_uses_foo();
};

But it must be used like that:

Der temp();
X x(temp);
x.complicated_function_that_uses_foo();

And it can be easily misused:

X x(Der());
x.complicated_function_that_uses_foo(); //calling pure virtual method

I thought about pointers, but pointers are evil.. erm, I mean that I
haven't came up with anything "nice" using pointers.

Any ideas on how it _should_ be done?

Thanks in advance.
 
T

tom

I don't know what you meant. I get your code compiled, and found that
the misused scenario you pointed out actually doesn't pass the
compilation, see the comment in the code below:

#include <iostream>
using namespace std;

class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
public:
Der1():Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}
};

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};

int _tmain(int argc, _TCHAR* argv[])
{
Der1 temp;
X x(temp);

//X x(Der1()); //error: this line can't be compiled,
//in vs I got an error: C4930
x.complicated_function_that_uses_foo();
return 0;
}
 
B

BobR

mati said:
Hi Here is the code:
class Base{ public:
Base(){...}
virtual ~Base(){}
virtual void foo() const =0;
};
class Der1 : public Base { public:
Der():Base() {...}
~Der() {...}
void foo() const {...}
};
There are several Der.. classes, and the problem is that I want to make
some X class, that will have a handle to the Base, in order to use
polymorphism.
Initialization of X objects will determine which actual object in the
Base's hierarchy will be used (Der1 or Der2 or ..), but I have no idea
how to do that in "nice" way.
Any ideas on how it _should_ be done?
Thanks in advance.

Not sure what you are trying to do. Maybe the 'Command pattern'
(modified for downcast) will give you an idea.

#include <iostream>
#include <vector>
// ---------------------
class Command{ public:
virtual ~Command(){}
virtual void execute(std::eek:stream&)const = 0;
};
// ---------------------
class HelloWorld : public Command { public:
void execute(std::eek:stream& eout)const{
eout << "Hello World! ";
}

void ExtraFunc(std::eek:stream& eout){eout<<std::endl;}

};
// ---------------------
class IAm : public Command { public:
void execute(std::eek:stream& eout)const{
eout << "I'm the command pattern!";
}
};
// ---------------------

// - Object that holds Commands: -
class RunCom{
std::vector<Command*> commands;
std::eek:stream &out;
public:
RunCom(std::eek:stream &rcout):eek:ut(rcout){}
// ---------------------
void Add(Command &c){ commands.push_back(&c); }
void Add(Command *c){ commands.push_back(c); } // for 'new'
// ---------------------
void Run(){
std::vector<Command*>::iterator it( commands.begin() );
while( it != commands.end() ){
// (*it++)->execute( out );
(*it)->execute(out);

// - you need to cast -
HelloWorld *hw = dynamic_cast<HelloWorld*>( *it );
if( hw ){ hw->ExtraFunc( out );}
// else{ out<<" not cast "<<std::endl;}

++it;
} // while(it)
} file://Run()
// ------------------------------------
void RunDel(){ // for 'new'
std::vector<Command*>::iterator it( commands.begin() );
while( it != commands.end() ){
(*it)->execute( out );

// - you need to cast -
HelloWorld *hw = dynamic_cast<HelloWorld*>( *it );
if( hw ){ hw->ExtraFunc( out );}

delete *it; *it = 0;
*it++;
} file://while(it)
} file://RunDel()
// ------------------------------------
}; file://class RunCom
// ---------------------

int main(){
{
RunCom Rc( std::cout );
HelloWorld HellW;
Rc.Add( HellW );
IAm Popeye;
Rc.Add( Popeye );
Rc.Run();
}

RunCom Rc2( std::cout );
Rc2.Add( new HelloWorld );
Rc2.Add( new IAm );
Rc2.RunDel();

return 0;
} // main()

If you can't adopt that, you may need something along the line of
'[Abstract] Factory pattern'.
 
M

mati

tom said:
I don't know what you meant. I get your code compiled, and found that
the misused scenario you pointed out actually doesn't pass the
compilation, see the comment in the code below:
You're right. It does not compile at gcc too.
I've cut too much code before posting, anyway, here is the code (a minor
modification of yours) that compiles, but is wrong, could you test it
please? And is it a bug in gcc, or I'm missing something? (probably the
latter...)


#include <iostream>
using namespace std;

class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
public:
Der1(int a,int b):Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}
};

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};

//int _tmain(int argc, _TCHAR* argv[])
int main()
{
Der1 temp(2,4);
X x(temp);

X x1(Der1(4,6)); // no error in gcc
x.complicated_function_that_uses_foo();
x1.complicated_function_that_uses_foo(); //here the progam
// exits with "pure virtual method called"
return 0;
}


#include <iostream>
using namespace std;

class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
public:
Der1():Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}
};

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};

int _tmain(int argc, _TCHAR* argv[])
{
Der1 temp;
X x(temp);

//X x(Der1()); //error: this line can't be compiled,
//in vs I got an error: C4930
x.complicated_function_that_uses_foo();
return 0;
}
 
M

mati

BobR said:
Not sure what you are trying to do. Maybe the 'Command pattern'
(modified for downcast) will give you an idea.

This is it, more or less, since the RunCom class will be derived from
Command, anyway it is not the point.
I've played around with it and my error was that I've tried to
initialize this X (RunCom) class (I don't need the Add function, all can
be done in the constructor) with the const Base& (const Command&), and
this could lead to this "easy misuse". Throwing away the const solved it
 
B

BobR

mati said:
You're right. It does not compile at gcc too.
I've cut too much code before posting, anyway, here is the code (a minor
modification of yours) that compiles, but is wrong, could you test it
please? And is it a bug in gcc, or I'm missing something? (probably the
latter...)


#include <iostream>
using namespace std;

class Base { public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base { public:
Der1(int a,int b):Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}
};

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo(){
ref.foo();
};
Remove that semicolon.

}; // this semicolon IS needed.

file://int _tmain(int argc, _TCHAR* argv[])
int main(){
Der1 temp(2,4);
X x(temp);

X x1(Der1(4,6)); // no error in gcc
x.complicated_function_that_uses_foo();
x1.complicated_function_that_uses_foo(); file://here the progam
// exits with "pure virtual method called"

Because you did not 'define it. see below.
return 0;
}

The problem is that you call a pure virtual func that was never defined.

class Base{ public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

Now, outside the class definition, you do (you can't do it 'inline'):

Base::foo()const{ cout<<"Base::foo()"; }
 
T

tom

The misuse is caused by the Der1 object created by the statement: "X
x1(Der1(4,6));" destroyed immediately after used as a parameter to
construct x1. So the solution here is to have this anonymous Der1
object live longer, one way to do is to have the X object make a copy
of it.



class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
private:
string mname;
public:
Der1(int a,int b, string name=""):mname(name),Base() { }
~Der1() {cout<<endl<<"destroyed "<<mname;}
virtual void foo() const { cout<<"der1";}
};

template
<typename DerType>
class X {
private:
const DerType ref;
public:
X(const DerType& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};

//int _tmain(int argc, _TCHAR* argv[])
int main()
{
Der1 temp(2,4, "normal use");
X<Der1> x(temp);

X<Der1> x1(Der1(4,6, "incorrect use")); // no error in gcc,
// tom: no error comfirmmed in vs c++, but after
// xl is constructed successfully, the object from
// Der1(4,6, "incorrect use") is destroyed immediately,
you will see this by
// run this
program and debug it step by step

x.complicated_function_that_uses_foo();
x1.complicated_function_that_uses_foo(); //here the progam
// exits with "pure virtual method called"
return 0;
}


class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};

class Der1 : public Base {
private:
string mname;
public:
Der1(int a,int b, string name=""):mname(name),Base() { }
~Der1() {cout<<endl<<"destroyed "<<mname;}
virtual void foo() const { cout<<"der1";}
};

template
<typename DerType>
class X {
private:
const DerType ref;
public:
X(const DerType ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};

//int _tmain(int argc, _TCHAR* argv[])
int main()
{
Der1 temp(2,4, "normal use");
X<Der1> x(temp);

X<Der1> x1(Der1(4,6, "incorrect use")); // no error in gcc,
// tom: comfirmmed in vs c++, but after
// xl is constructed successfully, the object from
// Der1(4,6, "incorrect use") is destroyed immediately
x.complicated_function_that_uses_foo();
x1.complicated_function_that_uses_foo(); //here the progam
// exits with "pure virtual method called"
return 0;
}




tom said:
I don't know what you meant. I get your code compiled, and found that
the misused scenario you pointed out actually doesn't pass the
compilation, see the comment in the code below:

You're right. It does not compile at gcc too.
I've cut too much code before posting, anyway, here is the code (a minor
modification of yours) that compiles, but is wrong, could you test it
please? And is it a bug in gcc, or I'm missing something? (probably the
latter...)

#include <iostream>
using namespace std;

class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;

};

class Der1 : public Base {
public:
Der1(int a,int b):Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}

};

class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};

};

//int _tmain(int argc, _TCHAR* argv[])
int main()
{
Der1 temp(2,4);
X x(temp);

X x1(Der1(4,6)); // no error in gcc
x.complicated_function_that_uses_foo();
x1.complicated_function_that_uses_foo(); //here the progam
// exits with "pure virtual method called"
return 0;





}
#include <iostream>
using namespace std;
class Base {
public:
Base() {}
virtual ~Base() {}
virtual void foo() const =0;
};
class Der1 : public Base {
public:
Der1():Base() { }
~Der1() {}
virtual void foo() const { cout<<"der1";}
};
class X {
const Base& ref;
public:
X(const Base& ref):ref(ref) {}
~X() {}
void complicated_function_that_uses_foo()
{
ref.foo();
};
};
int _tmain(int argc, _TCHAR* argv[])
{
Der1 temp;
X x(temp);
//X x(Der1()); //error: this line can't be compiled,
//in vs I got an error: C4930
x.complicated_function_that_uses_foo();
return 0;
}
 
M

mati

tom said:
The misuse is caused by the Der1 object created by the statement: "X
x1(Der1(4,6));" destroyed immediately after used as a parameter to
construct x1. So the solution here is to have this anonymous Der1
object live longer, one way to do is to have the X object make a copy
of it.

Sorry I haven't written this, I'm implementing the class and I've
wondered about using it later (or by someone else). Using "const" in X
class constructor is IMO a request for trouble here (program compiles
but has a major error). The X class constructor with _non-const_
references to Base gives compile errors if I try to use it like that:
x_(Der1(4,6));

Anyway, thanks for help.

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is so annoying in them?
A: Because you write very annoying posts.
Q: And why BobR is right?
 

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,773
Messages
2,569,594
Members
45,113
Latest member
Vinay KumarNevatia
Top