Re: Does Liskov's principle hold also for struct?
DeMarcus wrote:
Liskov's Substitution Principle says that public inheritance must always
model "is-a" or "works-like-a". But what about behaviorless structs?
I want to get away from global variables and create something I call
regional variables; something in between global and local. The regional
variables will be passed to objects as an "environment" struct.
For example:
struct BasicEnvironment
{
Logger* logger;
};
class MyClass
{
public:
MyClass( BasicEnvironment env ) { env.logger->log( "MyClass" ); }
};
Is there "&" missing here?
Now, if I want to extend the environment I have two options:
struct ExtendedEnvironment : public BasicEnvironment
{
char* homeDirectory;
};
or
struct ExtendedEnvironment
{
BasicEnvironment basicEnvironment;
char* homeDirectory;
};
Wherever I read it's recommended to use composition instead of
inheritance, but the discussions are always about classes and not about
behaviorless structs. If I use composition here I won't be able to add
something like
virtual void setEnvironment( Environment* env );
to MyClass in the future.
What is Environment? BasicEnvironment?
Consider this:
class Foo {
public:
virtual func(BasicEnvironment * env) = 0;
};
class Bar : public Foo {
public:
virtual func(BasicEnvironment * env) {
DerivedEnvironment * der_env = dynamic_cast ... bla bla
if (!der_env) throw ... bla bla
}
};
Although this would work, you cannot give the same environment to all
your objects. Each requires it's own type, but which one it is?
This can only be deduced by reading documentation, not by interface.
Does the following design work for you? (in which case I'll send you
my bank account no. :-)
class Foo {
public:
void func() {
get_env().logger->log("func");
}
protected:
virtual const BasicEnvironment & get_env() const = 0;
};
class Bar_with_inherited_env : public Foo {
public:
void set_env(const DerivedEnvironment & env) { m_env = env; }
protected:
virtual const DerivedEnvironment & get_env() const {
return m_env;
}
private:
DerivedEnvironment m_env;
};
class Bar_with_composed_env : public Foo {
public:
void set_env(const DerivedEnvironment & env) { m_env = env; }
protected:
virtual const BasicEnvironment & get_env() const {
return m_env.basicEnvironment;
}
private:
DerivedEnvironment m_env;
};
See... both work. My choice would be composition. But I'd provide
two or more separate environments...
class BasicEnvironment;
class HomeEnvironment;
class BarEnvironment {
BasicEnvironment basic;
HomeEnvironment home;
};
--
Dragan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]