473,395 Members | 1,377 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Casting class1<class2> to class1<class3 >

I'm using a library where the supplier has provided base class 'foo',
and a reference counting class which wraps 'foo':

------------------- library code -----------------------
template<class T>
refcount {
... // reference counting wrapper; like shared_ptr
};

class foo {
...
};

typedef refcount<foo> fooref;
--------------------------------------------------------

Now, when I use the library, I have to derive from 'foo' to make it
useful. I also have to add a new function which is *not* declared
virtual in 'foo':

----------------------- my code ------------------------
class myfoo : public foo {
...
void myfunc(void);
}
--------------------------------------------------------

Problem: if I know that a 'fooref' actually points to a 'myfoo', how
do I call 'myfunc'?

void a(fooref b) {
b->myfunc(); // compiler error: foo has no myfunc
static_cast<myfooref>(b)->myfunc(); // 1
static_cast<myfoo *>(&*b)->myfunc(); // 2
}

Both (1) and (2) compile, but are they the same thing? I understand
(2), but (1) is more confusing. Can I cast a templated class in this
way?

Cheers

AL
Jul 23 '05 #1
3 2315
On 2005-06-27, Andy Lomax <abuse@[> wrote:
I'm using a library where the supplier has provided base class 'foo',
and a reference counting class which wraps 'foo':

------------------- library code -----------------------
template<class T>
refcount {
... // reference counting wrapper; like shared_ptr
};

class foo {
...
};

typedef refcount<foo> fooref;
--------------------------------------------------------

Now, when I use the library, I have to derive from 'foo' to make it
useful. I also have to add a new function which is *not* declared
virtual in 'foo':

----------------------- my code ------------------------
class myfoo : public foo {
...
void myfunc(void);
}
--------------------------------------------------------

Problem: if I know that a 'fooref' actually points to a 'myfoo', how
do I call 'myfunc'?

void a(fooref b) {
b->myfunc(); // compiler error: foo has no myfunc
static_cast<myfooref>(b)->myfunc(); // 1
static_cast<myfoo *>(&*b)->myfunc(); // 2
}

Both (1) and (2) compile, but are they the same thing? I understand
(2), but (1) is more confusing. Can I cast a templated class in this
way?


You can't generally cast anything to anything, no (and the different
parametrizations *are* allowed to be as unrelated as you like -- for example,
you could specialise one of them to inherit from vector<int>, and another to
inherit list<void*> if you wanted to). Depending on what conversion operators
refcount supports, it might work.

Now some thoughts --
(1) If you're casting down a class heirarchy, it would be safer to use a
dynamic cast. Then you get a runtime check to make sure you are really right
(and that it does really point to what you think it does)

(2) But it's better to avoid this. What is stopping you from making void a()
take a parameter of type myfoo instead ? If you've got several derived classes
of foo, you could factor them into a common base class. There are legitimate
uses for downtime casting, but the abuses are more common than the uses.

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/
Jul 23 '05 #2
On Mon, 27 Jun 2005 12:14:57 +0000 (UTC), Donovan Rebbechi
<ab***@aol.com> wrote:
You can't generally cast anything to anything, no (and the different
parametrizations *are* allowed to be as unrelated as you like -- for example,
you could specialise one of them to inherit from vector<int>, and another to
inherit list<void*> if you wanted to). Depending on what conversion operators
refcount supports, it might work.
Ah.. forgotten about conversion operators. I've checked refcount, and
the only conversion op it has is:

template<class T>
class refcount {
operator T* () const { return static_cast<T*>(ref->ptr); }
};

So the code compiles anyway even without a conversion operator.
Now some thoughts --
(1) If you're casting down a class heirarchy, it would be safer to use a
dynamic cast. Then you get a runtime check to make sure you are really right
(and that it does really point to what you think it does)
Thanks. Presumably the dynamic_cast overhead is higher, though, so I
should stick with static_cast if I can guarantee no problems?
(2) But it's better to avoid this. What is stopping you from making void a()
take a parameter of type myfoo instead ? If you've got several derived classes
of foo, you could factor them into a common base class. There are legitimate
uses for downtime casting, but the abuses are more common than the uses.
Two reasons:
(a) the base 'foo' provides a lot of routines that I need, and they
all return a 'fooref', so I can't assign the result to a
refcount<myfoo> without downcasting anyway (ie. the problem just
moves):

typedef refcount<myfoo> myfooref;

void a(myfooref b) {
b->myfunc(); // Ok; solves immediate problem, but...
myfooref c = b->x(); // doesn't compile: x returns a fooref
myfooref d = static_cast<myfooref>(b->x()); // Ok
}

(b) This is a bit more nebulous. I'm not sure why, but it seems to me
that my own code should be written to use the original base class as
much as possible, rather than forcing use of my own subclass.
If you've got several derived classes
of foo, you could factor them into a common base class.


As it happens, the library provides 'foo'; I derive 'myfoo' from it; I
then derive another 60-odd classes from 'myfoo'.

Cheers

AL
Jul 23 '05 #3
On 2005-06-27, Andy Lomax <abuse@[> wrote:
On Mon, 27 Jun 2005 12:14:57 +0000 (UTC), Donovan Rebbechi Two reasons:
(a) the base 'foo' provides a lot of routines that I need, and they
all return a 'fooref', so I can't assign the result to a
refcount<myfoo> without downcasting anyway (ie. the problem just
moves):

typedef refcount<myfoo> myfooref;

void a(myfooref b) {
b->myfunc(); // Ok; solves immediate problem, but...
myfooref c = b->x(); // doesn't compile: x returns a fooref
myfooref d = static_cast<myfooref>(b->x()); // Ok
}
My first thought was covariant return types, but of course that's not
going to work because the return value isn't a pointer, it's a smart
pointer.
(b) This is a bit more nebulous. I'm not sure why, but it seems to me
that my own code should be written to use the original base class as
much as possible, rather than forcing use of my own subclass.
If you've got several derived classes
of foo, you could factor them into a common base class.


As it happens, the library provides 'foo'; I derive 'myfoo' from it; I
then derive another 60-odd classes from 'myfoo'.


Sounds like a good way to do it.

I wonder if there's a way you could contain the problem ? For example, by
writing a class whose responsibility is to take care of the downcasting.
It's a similar idea to auto_ptr or even scoped_ptr -- the point of the
class is to encapsulate the potentially dangerous operation (in this case,
downcasting). You'd implement it by giving it the same interface as myfoo,
except functions that return fooref would be adapted to return myfooref.
You could do this via private inheritance for example, and just delegate
calls to the contained myfooref object.

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/
Jul 23 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Scott Brady Drummonds | last post by:
Hi, everyone, I've checked a couple of on-line resources and am unable to determine how reinterpret_cast<> is different from static_cast<>. They both seem to perform a compile-time casting of...
20
by: Anonymous | last post by:
Is there a non-brute force method of doing this? transform() looked likely but had no predefined function object. std::vector<double> src; std::vector<int> dest; ...
40
by: fordge | last post by:
we usually use <<n as a cheaper option to multiplication when its factor of 2^n right, even for non 2^n say ix24 ==> ix(16+8) ==> (i<<4)+(i<<3) similarly divison 2^n is >>n
4
by: KC | last post by:
Could some one explain to me the casting rules for sending generic lists, ex. List<Person>, to a function that accepts List<object>? I cannot get the following easy-cheesy app to work. I get the...
4
by: matty.hall | last post by:
I have two classes: a base class (BaseClass) and a class deriving from it (DerivedClass). I have a List<DerivedClass> that for various reasons needs to be of that type, and not a List<BaseClass>....
3
by: Alex Maghen | last post by:
Hi. I'm a little confused about the code that resides in the code-behind of a MasterPage and the code that resides in the code-behind of the actual pages that USE that MasterPage. I'm noticing,...
0
by: submicron | last post by:
Hi All, I'm having problems implementing a readonly interface to a set of classes. Heres a simplification of the code: interface IreadonlyBase { // Does gets only on base class } class...
2
by: pallav | last post by:
I'm using an old sparse matrix C library in my C++ code and I'd like to know how to downcast a boost::shared_ptr to char *. The sparse matrix data structure is like this: struct...
10
by: Alex Vinokur | last post by:
Hi, Is it possible to do C++-casting from const pair<const unsigned char*, size_t>* to const pair<unsigned char*, size_t>* ? Alex Vinokur
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.