By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,024 Members | 1,332 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,024 IT Pros & Developers. It's quick & easy.

C# inheritance broken?

P: n/a
C# is an impressive language...but it seems to have one big limitation
that, from a C++ background, seems unacceptable.

Here's the problem:

I have a third-party Document class. (This means I can't change the
Document class.) I want to extend this (inherit from Document) as
MyDocument, adding new events and application-specific methods and
properties.

I submit that this can't be done in C#.

Consider this example:

class MyDocument : public Document

This doesn't work because the only way to open an existing Document is
using the static method Document.Load(string FileName), which returns a
Document object. There doesn't seem to be any way to convert or cast a
Document object to a MyDocument object. There is therefore no way to
"Load" a MyDocument object!
>From reading LOTS of posts on this group, the standard answers are:
1. "Wrap" the object, as follows:
class MyDocument
{
protected Document TheDocument;
}

But...this means that I have to wrap EACH of the hundreds of methods
and properties needed to manipulate the Document object. This is
clearly a case for inheritance, to allow the base class properties and
methods to be automatically available, with enhancements from the
derived class.

2. In MyDocument.Load, call Document.Load, and then COPY all of
Document's members to MyDocument.

BUT, this is prohibitive because COPYING all of Document's members is
prohibitive in terms of run time, and also in terms of development
effort (lines of code, and therefore, potential bugs).

In C++, I would do something like this:

class MyDocument : public Document
{
public static MyDocument Load(string FileName)
{
return (MyDocument)Document.Load(FileName);
}
}

So my conclusion is that C# inheritance is broken (in practice) because
of its strict type-checking, and no allowance for such a common
scenario.

Did I miss something?

Jan 26 '07
Share this Question
Share on Google+
64 Replies


P: n/a

<gr****@isaacsoft.comwrote in message
news:11**********************@a34g2000cwb.googlegr oups.com...
Jake Stevenson's posted an example earlier on this thread.

That's all fine, but it does not get around the cost of *copying* the
object.

I suppose that what I really want here is a sort of "reference"
constructor, something like the "Attach" method in ATL's CComPtr
class. Come to think of it, CComPtr actually "wraps" the interface
being used, but its wrapper is generated automatically by a
preprocessor. Too bad C# doesn't have an automatic wrapper generator
similar to the #import directive in C++!
What bastard variant of C++ has an "#import" directive?
Jan 30 '07 #51

P: n/a
That would be Microsoft Visual C++, all versions since at least 6.0.

On Jan 30, 11:40 am, "Mike Schilling" <a...@newsgroup.nospamwrote:
<gro...@isaacsoft.comwrote in messagenews:11**********************@a34g2000cwb.g ooglegroups.com...
Jake Stevenson's posted an example earlier on this thread.
That's all fine, but it does not get around the cost of *copying* the
object.
I suppose that what I really want here is a sort of "reference"
constructor, something like the "Attach" method in ATL's CComPtr
class. Come to think of it, CComPtr actually "wraps" the interface
being used, but its wrapper is generated automatically by a
preprocessor. Too bad C# doesn't have an automatic wrapper generator
similar to the #import directive in C++!What bastard variant of C++ has an "#import" directive?
Jan 30 '07 #52

P: n/a
Usage of #import:

#import <filename.ocx>

Just typing this line in Visual Studio will generate a .h and a .cpp
file wrapping all of the methods and properties of an OCX control.

On Jan 30, 11:40 am, "Mike Schilling" <a...@newsgroup.nospamwrote:
<gro...@isaacsoft.comwrote in messagenews:11**********************@a34g2000cwb.g ooglegroups.com...
Jake Stevenson's posted an example earlier on this thread.
That's all fine, but it does not get around the cost of *copying* the
object.
I suppose that what I really want here is a sort of "reference"
constructor, something like the "Attach" method in ATL's CComPtr
class. Come to think of it, CComPtr actually "wraps" the interface
being used, but its wrapper is generated automatically by a
preprocessor. Too bad C# doesn't have an automatic wrapper generator
similar to the #import directive in C++!What bastard variant of C++ has an "#import" directive?
Jan 30 '07 #53

P: n/a
Mike Schilling wrote:
<gr****@isaacsoft.comwrote in message
news:11**********************@l53g2000cwa.googlegr oups.com...
[...]
But you haven't shown a C++ solution either, since the cast in your example
doesn't work.
If a constructor is added like in the following example, it will work.
Think that was the intention of Tony.

class Document
{
public:
Document(){}
static Document Load() { return Document(); }
};

class MyDocument : public Document
{
public:
MyDocument() {}
MyDocument(Document& s) : Document(s) {}
static MyDocument Load() { return Document::Load(); }
};

int main(int argc, char* argv[])
{
MyDocument s = MyDocument::Load();
return 0;
}

Andre

Jan 30 '07 #54

P: n/a
gr****@isaacsoft.com wrote:
Jake Stevenson's posted an example earlier on this thread.

[...]

preprocessor. Too bad C# doesn't have an automatic wrapper generator
similar to the #import directive in C++!
It should have one, since it will generate a Interop DLL if you add a
COM dll reference. But why don't you automatically write and let a small
program do you this for you via reflection ? Should be fairly simple to
generate a MyDocument class with all the methods of Document
implemented, which all are delegating the call to an internal Document
object ?

By the way a object holding more than 100 methods, is IMHO somewhat
overloaded with methods - but that's another story.

Andre
Jan 30 '07 #55

P: n/a
Andre,

That's great for C++. But in C# you can't set "base" in a
constructor.

Tony

On Jan 30, 2:48 pm, Andre Kaufmann <andre.kaufmann_re_mo...@t-
online.dewrote:
Mike Schilling wrote:
<gro...@isaacsoft.comwrote in message
news:11**********************@l53g2000cwa.googlegr oups.com...
[...]
But you haven't shown a C++ solution either, since the cast in your example
doesn't work.

If a constructor is added like in the following example, it will work.
Think that was the intention of Tony.

class Document
{
public:
Document(){}
static Document Load() { return Document(); }

};

class MyDocument : public Document
{
public:
MyDocument() {}
MyDocument(Document& s) : Document(s) {}
static MyDocument Load() { return Document::Load(); }

};

int main(int argc, char* argv[])
{
MyDocument s = MyDocument::Load();
return 0;

}

Andre

Jan 30 '07 #56

P: n/a
Reflection is no good, because of the amount of time it takes to make
a copy for a large document.

BTW, you'll find lots of properties and methods, buried many layers
deep, in IWebBrowser and IHtmlDocument also.

Tony

On Jan 30, 2:57 pm, Andre Kaufmann <andre.kaufmann_re_mo...@t-
online.dewrote:
gro...@isaacsoft.com wrote:
Jake Stevenson's posted an example earlier on this thread.
[...]
preprocessor. Too bad C# doesn't have an automatic wrapper generator
similar to the #import directive in C++!

It should have one, since it will generate a Interop DLL if you add a
COM dll reference. But why don't you automatically write and let a small
program do you this for you via reflection ? Should be fairly simple to
generate a MyDocument class with all the methods of Document
implemented, which all are delegating the call to an internal Document
object ?

By the way a object holding more than 100 methods, is IMHO somewhat
overloaded with methods - but that's another story.

Andre

Jan 30 '07 #57

P: n/a
Hi,

<gr****@isaacsoft.comwrote in message
news:11**********************@l53g2000cwa.googlegr oups.com...
|No, it's simply bad design of the base class, or trying to made a bad use
of
| the class.
|
| You say the base class is designed poorly. So what would a GOOD
| design look like? The constraints are:
| - Original 'Document' object has been serialized as a 'Document.'
| - Reflection (to make a copy) is impractical because it is time-
| intensive.
| - Wrapping (MyDocument "contains" a Document" is impractical because
| of the large numbers of methods that would have to be reproduced.

What about:

class D{

public D( string file ) { LoadDoc(file); }
protected virtual void LoadDoc( string file ) {}
}

class D1:D
{
public D1( string file ):base(file){}
protected override void LoadDoc( string file )
{
base.LoadDoc();
// my stuff
}

public static D1 GetD1( string file ){ return new D1( file ); }

}

You then can do D1.GetD1( file) and get a D1
--
Ignacio Machin
machin AT laceupsolutions com
Jan 30 '07 #58

P: n/a
Ignacio,

That would work great, except that serialization (used by LoadDoc to
read the document from a file) does not load a new object into "this"
or "base". It always creates a new object of whatever type was
originally serialized, in this case, a Document object. This new
Document object cannot be cast to a MyDocument, nor can it be assigned
to "this" or "base", because these are always read-only.

Tony

On Jan 30, 4:55 pm, "Ignacio Machin \( .NET/ C# MVP \)" <machin TA
laceupsolutions.comwrote:
Hi,

<gro...@isaacsoft.comwrote in message

news:11**********************@l53g2000cwa.googlegr oups.com...
|No, it's simply bad design of the base class, or trying to made a bad use
of
| the class.
|
| You say the base class is designed poorly. So what would a GOOD
| design look like? The constraints are:
| - Original 'Document' object has been serialized as a 'Document.'
| - Reflection (to make a copy) is impractical because it is time-
| intensive.
| - Wrapping (MyDocument "contains" a Document" is impractical because
| of the large numbers of methods that would have to be reproduced.

What about:

class D{

public D( string file ) { LoadDoc(file); }
protected virtual void LoadDoc( string file ) {}

}

class D1:D
{
public D1( string file ):base(file){}
protected override void LoadDoc( string file )
{
base.LoadDoc();
// my stuff

}

public static D1 GetD1( string file ){ return new D1( file ); }

}

You then can do D1.GetD1( file) and get a D1

--
Ignacio Machin
machin AT laceupsolutions com

Jan 31 '07 #59

P: n/a
gr****@isaacsoft.com wrote:
Andre,

That's great for C++. But in C# you can't set "base" in a
constructor.
Was only a valid sample of how to do it in C++. In C# surely you can't
do this.

Andre
Jan 31 '07 #60

P: n/a
gr****@isaacsoft.com wrote:
Reflection is no good, because of the amount of time it takes to make
a copy for a large document.
It wasn't my intention to use reflection directly, but to use it to
create new source code, which has implemented all methods of the
Document object, so that you don't have to do the wrapping by "hand".

Andre
Jan 31 '07 #61

P: n/a
http://www.codeproject.com/csharp/WrapiAddin.asp
"Andre Kaufmann" <an*********************@t-online.dewrote in message
news:eq**************@TK2MSFTNGP03.phx.gbl...
gr****@isaacsoft.com wrote:
>Reflection is no good, because of the amount of time it takes to make a
copy for a large document.

It wasn't my intention to use reflection directly, but to use it to create
new source code, which has implemented all methods of the Document object,
so that you don't have to do the wrapping by "hand".

Andre


Jan 31 '07 #62

P: n/a
On Jan 30, 12:48 pm, Andre Kaufmann <andre.kaufmann_re_mo...@t-
online.dewrote:
Mike Schilling wrote:
<gro...@isaacsoft.comwrote in message
news:11**********************@l53g2000cwa.googlegr oups.com...
[...]
But you haven't shown a C++ solution either, since the cast in your example
doesn't work.

If a constructor is added like in the following example, it will work.
Think that was the intention of Tony.

class Document
{
public:
Document(){}
static Document Load() { return Document(); }

};

class MyDocument : public Document
{
public:
MyDocument() {}
MyDocument(Document& s) : Document(s) {}
static MyDocument Load() { return Document::Load(); }

};

int main(int argc, char* argv[])
{
MyDocument s = MyDocument::Load();
return 0;

}
Aren't you forgetting something? Where is the copy constructor for
Document that accepts a pointer to a Document and creates a new
document from it? (Invoked on the line:

MyDocument(Document& s) : Document(s) {}

) Or is this copy constructor somehow automatically generated by the C
++ compiler?

Jan 31 '07 #63

P: n/a
Bruce Wood wrote:
[...]
MyDocument(Document& s) : Document(s) {}

) Or is this copy constructor somehow automatically generated by the C
++ compiler?

Exactly. C++ will automatically generate a copy constructor on a binary
basis (memcopy) or will call a user defined one for each of the class
variables. However, a developer can make the copy constructor private in
a class and then you surely can't construct an object as I did in the
example.

Andre

Feb 1 '07 #64

P: n/a
Hi,

"Jake Stevenson" <ja***********@gmail.comwrote in message
news:11**********************@q2g2000cwa.googlegro ups.com...
>
Something similar can be implemented in the base class and would be
inherited by your class. There may be a performance issue with
Reflection though.
In C++ I remember this idea has a name, a copycon constrctor?

What strike me as weird is what is the problem in handling a Docment in the
first place, IMO MyDocument extend Document but the application should be
made to handle Document as default. And finally the readed file IS A
document.

Feb 4 '07 #65

64 Replies

This discussion thread is closed

Replies have been disabled for this discussion.