Monday, June 15, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 5 topics

Paavo Helde <myfirstname@osa.pri.ee>: Jun 14 08:24PM -0600

Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> wrote in
 
> In modern C++ we should avoid using 'int' and its associates such as
> 'short' and 'long' as they are all non-portable and unsafe (their size
> and value range can differ from one implementation to the next);
instead
> one should use the typedefs from <cstdint> instead.
 
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
 
Note that the actually needed range often depends on the application
domain requirements and the hardware capabilities, both of which are out
of the control of the programmer and can change in time. So, at the time
of writing the programmer often does not have sufficient knowledge to
select the "correct" fixed-size type. The only exception is when it is
known that the numbers are relatively small and the limits do not matter,
and this is exactly what the generic int type is meant for.
 
For example, it used to be that the number of pixels in a single medical
image (2D or 3D) fits in 32 bits, but this assumption is slowly starting
to break. So all those apps who have used e.g. std::uint32_t for the
pixel index type will probably need a potentially painful upgrade cycle
in the future.
 
Instead of relying on a fixed type, the program should define a typedef
for each different usage case of int, which can be upgraded more cleanly
and easily when the need arises. The typedef itself can be based on a
fixed-size type or then not, this is not so crucial any more.
 
This is not something new, there is a reason why STL contains several
such typedefs as e.g. std::string::size_type. Using fixed-size types
would not be possible here. Fixed-size types should be directly used only
in places where the type sizes are indeed fixed, e.g. when composing a
TIFF file IFD in memory or something like that.
 
Cheers
Paavo
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Daniel <danielaparker@gmail.com>: Jun 14 07:01PM -0700

On Sunday, June 14, 2015 at 7:21:28 AM UTC-4, David Brown wrote:
> >> a little pedantic, to say the least of it?
 
> > How would you put it less pedantically?
 
> By writing "range" instead of "rage" - Daniel was making a pun on your typo.
 
Ben's follow up was actually pretty good, I was 90 percent certain that he had got my joke.
 
Daniel
Juha Nieminen <nospam@thanks.invalid>: Jun 15 09:00AM

> 'short' and 'long' as they are all non-portable and unsafe (their size
> and value range can differ from one implementation to the next); instead
> one should use the typedefs from <cstdint> instead.
 
"int" is traditionally the "natural" most efficient integer type of the
platform.
 
If you are going to use std::int32_t instead, then in some obscure
platforms that might not be the most efficient integral type.
(And "obscure" may not even mean "ancient". It could well be that
some (current or future) 64-bit system has efficient 64-bit ints
and inefficient 32-bit integrals.)
 
It's probably safer to use std::int_least32_t if you want to ensure
safety, and the fact that the integral might have more than 32 bits
is a non-issue.
 
std::int32_t ought to be used only if you need *exactly* 32 bits
(eg. because you are handling some binary format, or require this
for memory usage reasons.)
 
In practice 'int' is just fine. If your library/program requires
values that are outside the range of a 16-bit ingeter, and you want
to make 100% sure that your library won't break, add a static_assert
that ensures it has enough bits.
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
gwowen <gwowen@gmail.com>: Jun 15 03:10AM -0700

On Saturday, June 13, 2015 at 7:27:28 PM UTC+1, Mr Flibble wrote:
 
 
> Using 'int' everywhere is you NOT choosing a type at all; it is just you
> not thinking properly about your problem domain so by your own words you
> are "idiotic".
 
Nice strawman. Who recommended using 'int' everywhere?
 
> The code you write must be really unsafe;
 
Nope.
gwowen <gwowen@gmail.com>: Jun 15 03:11AM -0700

On Saturday, June 13, 2015 at 9:24:01 PM UTC+1, Mr Flibble wrote:
 
> > Claimed but not shown.
 
> "their size and value range can differ from one implementation to the next"
 
> /Flibble
 
Wait, weren't you recommending size_t a minute ago?
 
But "their size and value range can differ from one implementation to the next" so size_t must, by this logic (and way I say logic, I am using the word quite wrongly) be unsafe.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 15 11:42AM +0100

On Sat, 13 Jun 2015 17:43:07 +0100
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> wrote:
[snip]
 
> auto i = 42s32; // signed, 32-bits
 
> or
 
> auto i = 42u32; // unsigned, 32-bits
 
The correct form for this kind of initialization in current C++11/14
if you want auto/template type deduction is:
 
auto i = std::int32_t{42};
 
auto i = std::uint32_t{42};
 
which also has the benefit of avoiding implicit narrowing conversions.
It seems good enough to me and I cannot see the point of yet more
unnecessary C++ syntax.
 
In addition, if you want minimum sizes you would be better off in most
cases using std::int_least32_t and std::uint_least32_t, as others have
said.
 
Chris
David Brown <david.brown@hesbynett.no>: Jun 15 07:13AM -0600

On 15/06/15 04:24, Paavo Helde wrote:
 
> Sorry, int is extremely portable, every C and C++ implementation has it
> and it is guaranteed to work in a pretty large range (the actual range
> can be checked quite easily via std::numeric_limits, BTW).
 
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
 
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
 
 
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
 
Personally, I have very little use of "short" or "long", however. Bar
consistency with existing code, I can't see any use of "(unsigned)
short" that would not be better suited with "(u)int16_t", nor any use of
"long" that would not be better with "int32_t" or "int64_t", according
to what you actually /need/. And I think "unsigned char" and "signed
char" are meaningless monstrosities - plain "char" is good for character
data, while "uint8_t" and "int8_t" are appropriate for data bytes and
small unsigned or signed numbers. (On platforms without 8-bit chars,
(u)int_least8_t is better than (un)signed char.)
 
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
legalize+jeeves@mail.xmission.com (Richard): Jun 15 02:53PM

[Please do not mail me a copy of your followup]
 
gwowen <gwowen@gmail.com> spake the secret code
 
>On Saturday, June 13, 2015 at 7:27:28 PM UTC+1, Mr Flibble wrote:
 
>> Using 'int' everywhere is you NOT choosing a type at all;
 
Nonsense. It is choosing a type: signed integer.
 
>> not thinking properly about your problem domain so by your own words you
>> are "idiotic".
 
>Nice strawman. Who recommended using 'int' everywhere?
 
Stroustrup, actually. I'm pretty sure in "The C++ Programming
Language" he recommends only using the specifically sized integer types
when you are certain that it really *needs* to be that size. An
example would be a 2-byte signed integer quantity read from a binary
byte stream using std::istream::read.
 
When I've looked at code that is littered with int32_t all over the
place, I find it not only ugly but it violates the open/closed
principle for design. 99.9999% of the time the 32-bitness of the
integer was not essential or important for the code, they simply
adopted that simple minded notion that everything should explicitly
declare integers of specific sizes.
 
Yes, C/C++ has a language model that more closely maps to the
underlying machine, giving it a nice efficient mapping to instructions.
But that doesn't mean we should turn all our C/C++ source code into
thinly veiled assembly language with everything forced into WORD,
DWORD, and QWORD quantities. (The Windows API makes this mistake --
WORD is 16 bits regardless of the actual size of the machine word!)
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
scott@slp53.sl.home (Scott Lurndal): Jun 15 02:58PM


>> int32_t i = 42;
 
>Why must one reserve 32bits for 42, if it can be stored in an int which
>is, say, 16bit long?
 
Because it doesn't have the const attribute?
legalize+jeeves@mail.xmission.com (Richard): Jun 15 03:06PM

[Please do not mail me a copy of your followup]
 
slp53@pacbell.net spake the secret code
 
>>Why must one reserve 32bits for 42, if it can be stored in an int which
>>is, say, 16bit long?
 
>Because it doesn't have the const attribute?
 
Clearly it needs to be stored in uint6_t.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jun 15 03:36AM

[Please do not mail me a copy of your followup]
 
Noob <root@127.0.0.1> spake the secret code
 
>> Instead crank up the warning level on your compiler to have it tell you
>> which members are uninitialized.
 
>You don't say why the latter is better?
 
At the risk of repeating myself once again: please stop writing C style
code in a C++ program. C++ is not C, it is a different language that
provides a large amount of interoperability with C code, but it is not
C.
 
std::memset is the way that C zeroes a chunk of bytes. If those chunk
of bytes happen to be a structure layout for which "initialized" is
the same thing as setting all the bytes in the structure to zero, then
it can be thought of as "initializing" the structure. (This is often
not the case, even in C; members of the structure may need to be set
to something other than zero in order to be consistent with the
preconditions of the data structure.)
 
C++ uses constructors to guarantee that an object, once constructed,
is ready for use and that all the invariants of the object have been
established. Constructors don't return error codes.
 
If the invariants can't be established by the constructor, then it is
common for the constructor to throw an exception, guaranteeing that you
either get a valid object, or nothing.
 
>The current constructor is ~60 lines of code.
 
So?
 
>In my (predominantly C) experience,
 
This isn't C. This is C++. C++ != C.
 
>clearing the entire struct with
>a single line communicates the intent more clearly, which results in
>less maintenance over time.
 
The reason this is the accepted idiom in C is because C doesn't have
constructors and can't establish invariants for an object represented
by a struct.
 
Constructors establish that intent explicitly in the language,
instead of idiomatically by some sort of agreed upon convention.
Constructors reveal the intent of initialization more clearly than C
because it is a proper construct in the language.
 
>If we are talking about a plain struct, there are no problems, right?
 
As already mentioned on this thread, you have a class with a non-trivial
constructor. It is already not a "plain old data" struct like those in C.
See section 8.2.6 Plain Old Data in "The C++ Programming Language",
Bjarne Stroustrup, 4th ed., pg. 210:
 
"For example, copying a 100-element array using 100 calls of a
copy constructor is unlikely to be as fast as calling std::memcpy(),
which typically simply uses a block-move machine instruction.
Even if the constructor is inlined, it could be hard for an
optimizer to discover this optimization. Such "tricks" are not
uncommon, and are important, in implementations of containers,
such as vector, and in low-level I/O routines.
 
**They are unnecessary and should be avoided in higher-level code.**"
(emphasis added.)
 
>(Although I seem to recall that C++'s "struct" is just a synonym for
>"class" with everything public.)
 
However, C++'s struct is not C's struct.
 
>If the class consists only of int fields + accessors, are there
>unforeseen drawbacks to zeroing with memset?
 
Yes, C++ provides explicit mechanisms for initialization and you
should use those and not C-style mechanisms. Initialization syntax
follows the "open/closed principle" of object-oriented design, but
std::memset does not.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Christian Gollwitzer <auriocus@gmx.de>: Jun 15 07:10AM +0200

Am 13.06.15 um 19:33 schrieb Noob:
>> value (true for IEEE floats, but...).
 
> I'm not sure what you meant by "discards the type information".
 
> In C too, it is not guaranteed that all-bits-0 pattern is 0.0 or NULL.
 
Yes, exactly. Wouldn't it be much nicer to initialize to a knwon value,
e.g. 0.0 or 3.14159... instead of just zero bits, which could be
anything, though in practice it's a sensible value for most data types?
 
> 40 methods
> };
 
> Would it still look simple then?
 
Well the syntax would then be something like
 
foo() : aa(0), bb(0), ... { code }
 
simple or not, your choice. But surely that "class" is not idiomatic
C++. These odd integer arrays, are Na, Nb big numbers? If so, you'd be
better off using a std:vector for memory management. Raw pointers to
other structures also look suspicious. Your constructor should probably
establish a link to a real object, maybe construct one, and dispose it
in the destructor (or decrese the refcount or similar)
 
 
>> int value = 5;
>> };
 
> Do g++ and Visual Studio support this syntax?
 
They should, depends on the version, since this is a C++11 feature.
Should be no problem if you use a current version.
 
 
> Thanks for the suggestion.
 
> (However, I'm afraid of the code churn, as it would mean
> touching all the class definitions.)
 
Your choice, depends on whether it's cheaper to fix the engine using
chewing gum and shoelace, or doing it right and spending lots of time to
have it running for years.
 
Christian
 
Noob <root@127.0.0.1>: Jun 15 08:08AM +0200

On 13/06/2015 11:32, Christian Gollwitzer wrote:
 
> };
 
> You could do that for all of your fields at the point where they are
> declared, so would be easy to spot a missing one.
 
What is the equivalent syntax for 0 initializing an int array?
 
int array[20] = { 0 };
 
like in C?
 
Also, can I omit the SomeClass(int) constructor if I don't
use it?
 
And can I omit the SomeClass() constructor, or does it have
to be defined to a NOP?
 
Regards.
Juha Nieminen <nospam@thanks.invalid>: Jun 15 08:41AM

> In my (predominantly C) experience, clearing the entire struct with
> a single line communicates the intent more clearly, which results in
> less maintenance over time.
 
It may also break the class in the future, if somebody adds a new
member to it that requires its own construction (and which would just
break if you zero all of its bits).
 
// Current version of your class:
class MyClass
{
int a, b, c, d;
double e, f, g;
 
public:
MyClass() { std::memset(...); }
};
 
// Future version of your class:
class MyClass
{
int a, b, c, d;
double e, f, g;
std::string str; // might break, depending on implementation
 
public:
MyClass() { std::memset(...); }
};
 
If you can use C++11, it's better to initialize all the members where
they are declared (rather than in the constructor). This makes it a lot
more obvious if a member is not being initialized.
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
legalize+jeeves@mail.xmission.com (Richard): Jun 15 02:35PM

[Please do not mail me a copy of your followup]
 
Noob <root@127.0.0.1> spake the secret code
>> declared, so would be easy to spot a missing one.
 
>What is the equivalent syntax for 0 initializing an int array?
 
> int array[20] = { 0 };
 
Value initialization:
<http://en.cppreference.com/w/cpp/language/value_initialization>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Paul <pepstein5@gmail.com>: Jun 15 06:28AM -0700

I wrote
std::vector<int> vect = {-1, 0, 1, 2, 3, -4, 4};
 
std::sort(vect.begin(), vect.end());
 
 
Using codeblocks, I put my cursor in the word begin and it reads const_iterator std::vector::begin()
 
Surely, this is wrong? vect.begin() is a non-const iterator, isn't it? Or am I missing something? Or is codeblocks just generally unreliable?
 
Thank you very much for your feedback.
 
Paul
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 15 09:34AM -0400

On 6/15/2015 9:28 AM, Paul wrote:
 
> Surely, this is wrong? vect.begin() is a non-const iterator, isn't
> it? Or am I missing something? Or is codeblocks just generally
> unreliable?
 
There are two versions of 'vector::begin' member function. Perhaps
codeblocks doesn't know which one to show and picks the apparently wrong
one...
 
V
--
I do not respond to top-posted replies, please don't ask
fl <rxjwg98@gmail.com>: Jun 14 05:09PM -0700

On Friday, June 12, 2015 at 8:53:53 AM UTC-7, fl wrote:
 
> Number *rep;
> short referenceCount;
> };
 
After reading a description about the above code snippet, I find that it is
possible helpful on the role of BaseConstructor. The code author try to
mimic a pure object-oriented language with C++. But I still cannot
understand the intention of BaseConstructor. I feel the code is
interesting to learn the technique involved. Could you help me on the role
of BaseConstructor?
 
Thanks,
 
 
.................
Motivation
In pure object-oriented languages like Smalltalk, variables are run-time
bindings to objects that act like labels. Binding a variable to an object
is like sticking a label on it. Assignment in these languages is analogous
to peeling a label off one object and putting it on another. On the other
hand, in C and C++, variables are synonyms for addresses or offsets instead
of being labels for objects. Assignment does not mean re-labelling, it
means overwriting old contents with new one. Algebraic Hierarchy idiom uses
delegated polymorphism to simulate weak variable to object binding in C++.
Algebraic Hierarchy uses Envelope Letter idiom in its implementation. The
motivation behind this idiom is to be able write code like the one below.
 
 
Number n1 = Complex (1, 2); // Label n1 for a complex number
Number n2 = Real (10); // Label n2 for a real number
Number n3 = n1 + n2; // Result of addition is labelled n3
Number n2 = n3; // Re-labelling
fl <rxjwg98@gmail.com>: Jun 14 06:48PM -0700

On Friday, June 12, 2015 at 8:53:53 AM UTC-7, fl wrote:
 
> Number *rep;
> short referenceCount;
> };
 
 
My another question is about '(int=0)' inside the struct. I cannot
understand it because 'int' is a reserved word. I never see such usage
before. Can you explain it to me?
 
Thanks,
 
 
struct BaseConstructor
{
BaseConstructor(int=0)
{}
};
Richard Damon <Richard@Damon-Family.org>: Jun 14 10:23PM -0400

On 6/14/15 9:48 PM, fl wrote:
> BaseConstructor(int=0)
> {}
> };
 
When declaring a function (or a constructor), as opposed to defining it,
the declaration is not required to include the variable names of the
parameters (as they aren't important).
 
You are also allowed to provide default values for the parameter if it
isn't provided.
 
A fuller version of the declaration would be
 
BaseConstructor(int i=0);
 
Because this constructor can be called with no parameters, it can be
used as the default constructor, which will act exactly like calling the
constuctor with a parameter of 0 (the default value defined)
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 02:06AM -0500

fl <rxjwg98@gmail.com> wrote in
>> BaseConstructor(int=0)
>> {}
>> };
 
[...]
 
>> {
>> protected:
>> Number (BaseConstructor);
[...]
> understand the intention of BaseConstructor. I feel the code is
> interesting to learn the technique involved. Could you help me on the
> role of BaseConstructor?
 
It appears BaseConstructor is only used in a protected constructor, so it
probably is meant as some kind of communication detail between derived
and base classes. It is not clear from these code examples how it is
used.

> Number n2 = Real (10); // Label n2 for a real number
> Number n3 = n1 + n2; // Result of addition is labelled n3
> Number n2 = n3; // Re-labelling
 
I would guess this passage is more about the rep and referenceCount
members. It is interesting to not that here both the "envelope" and
"letter" parts are both based on the same class (Number), which seems to
make the design much more complicated than needed. It is probably meant
for "automagically" allowing code like that:
 
Real x(10);
Complex y(1, 2);
Number z = x + y;
 
However, then also this is allowed:
 
x = y;
 
This seems quite confusing - is x now Real or Complex?
 
 
hth
Paavo
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 15 08:29AM -0400

On 6/14/2015 10:23 PM, Richard Damon wrote:
 
> Because this constructor can be called with no parameters, it can be
> used as the default constructor, which will act exactly like calling the
> constuctor with a parameter of 0 (the default value defined)
 
I think the OP's question is, why have 'BaseConstructor' at all. I am
perhaps too dense to try to think for the designer of the code, and so I
am not sure I divined the reason for having 'BaseConstructor' and to use
it to create a Number instance. I have a sneaky suspicion that it has
something to do with possibly initializing Number from an int, and to
prohibit such construction, which would be assisted in some way by
having a BaseConstructor convertible from an int. But to confirm that
one would need to take out BaseConstructor and see the effects, and I am
simply too lazy to experiment.
 
V
--
I do not respond to top-posted replies, please don't ask
fl <rxjwg98@gmail.com>: Jun 14 08:31PM -0700

Hi,
 
When I read the example class, I feel puzzled about "Number::~Number()"
after there is
 
virtual ~Number();
 
I remember that the derived class of Number should have a real
~Number();
 
 
Now, class Number has both virtual and member function
~Number().
 
 
Can you help me on this question?
 
 
Thanks for the expert keeping answer my questions.
 
 
 
 
 
 
////////////////////////////
struct BaseConstructor
{
BaseConstructor(int=0)
{}
};
 
class RealNumber;
class Complex;
class Number;
class Number
{
friend class RealNumber;
friend class Complex;
public:
Number ();
Number & operator = (const Number &n);
Number (const Number &n);
virtual ~Number();
virtual Number operator + (Number const &n) const;
void swap (Number &n) throw ();
 
static Number makeReal (double r);
static Number makeComplex (double rpart, double ipart);
protected:
Number (BaseConstructor);
 
private:
void redefine (Number *n);
virtual Number complexAdd (Number const &n) const;
virtual Number realAdd (Number const &n) const;
 
Number *rep;
short referenceCount;
};
 
Number::~Number()
{
if (rep && --rep->referenceCount == 0)
delete rep;
}
legalize+jeeves@mail.xmission.com (Richard): Jun 15 03:52AM

[Please do not mail me a copy of your followup]
 
What book is this you're reading so I can make sure *not* to recommend
it to anyone? LOL. I find the snippets you're posting to leave a
reader new to the language more confused than enlightened and they
often seem to exhibit poor practices and conventions. Introducing
someone to the language with poor practices and conventions is IMO a
really bad way to teach C++.
 
fl <rxjwg98@gmail.com> spake the secret code
 
>I remember that the derived class of Number should have a real
> ~Number();
 
If a class is designed to be used as a base class with virtual methods
that provide 'extension points' from the base class, such a base class
should have a virtual destructor.
 
The reason for this is that virtual methods are the mechanism by which
we obtain run-time polymorphism for a class hierarchy. In such a
sitaution, the user of such class is interacting with the class
through a pointer to the base class. When an instance of the class is
destroyed by operator delete, the virtual destructor ensures that the
destructor associated with the actual derived instance of the base is
invoked. If the destructor were not virtual, only the base class
would be destroyed and the object would not be properly destroyed.
 
>Now, class Number has both virtual and member function
>~Number().
 
It declares the destructor virtual and then defines the destructor.
 
> virtual ~Number();
 
This is a declaration.
 
> if (rep && --rep->referenceCount == 0)
> delete rep;
>}
 
This is a definition. When a virtual method is defined outside the
class declaration, the 'virtual' keyword is not allowed because only
declarations are marked virtual, not definitions.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 01:23AM -0500

fl <rxjwg98@gmail.com> wrote in news:265510a8-466d-4f31-b63a-fb8c1e210cc0
 
> virtual ~Number();
 
> I remember that the derived class of Number should have a real
> ~Number();
 
It looks like you are thinking that a virtual function may not have a
definition. This is not what 'virtual' means in C++, even pure virtual
functions can have definitions. Find a decent C++ tutorial and reread the
introduction to virtual member functions.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: