Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Implicit Virtual


March, 2005: Implicit Virtual

Herb Sutter (http://www.gotw.ca/) chairs the ISO C++ Standards committee and is an architect in Microsoft's Developer Division. His most recent books are Exceptional C++ Style and C++ Coding Standards (Addison-Wesley). Jim Hyslop is a senior software designer for Leitch Technology International. He can be reached at [email protected].


Isaid a word I really shouldn't have said that Monday afternoon when I found I was broken by Wendy's check-in. I caught myself with an embarrassed hand over my mouth, looked around, and fortunately nobody seemed to notice. I said less wicked things as I started rooting around to find the culprit.

"I heard that," Wendy muttered behind me.

I jumped. "Er, ah, eh, um," I stammered. "Um, hi."

"Hey, so-called pardner," she said darkly. "What's so important that you take it out on my ancestry?"

"I'm sorry, I've been pulling too many all-nighters, and Bob's been just horrible, and the cafeteria ran out of coffee, and I really didn't mean any..."

Fortunately, just then the Guru appeared. How she knew that I needed her then was a mystery to me, but apparently she did and helped to ease the tense situation. "My children," she glided toward us and stopped, resting a thick tome on the corner of my desk, "what is the matter?"

I somehow stammered through the story: "Wendy, uh, helpfully checked in an update to her class. Then my code that derived from the class behaved weirdly. Look, here's the code." I found the editor window and pulled it to the top. It looked something like this:

class MyClass : public Something, 
               private SomethingElse {
public:
  // ...
  void Function( int i );
};

"Okay," I explained, "so I've got MyClass here, see, with a Function and all. This has been checked in and working for months. People love it. But my tests all just broke."

Wendy blinked and wondered. "How come?"

"I'm not really sure," I admitted. "But the only thing that changed was that I took your new check-in."

"And what, pray, did break?" the Guru queried.

"Oh, specifically? Well, all of a sudden lots of calls to that Function started violating their test cases and doing odd stuff. It was pretty bizarre."

"Say," Wendy wondered, "what's Something and SomethingElse? I only changed a couple of small things in a few classes, and I didn't do anything to those to you're showing there."

"Well, hmm. Let's take a look." I browsed over to those classes, and their base classes, and their grandparent classes (it was a horribly thick hierarchy of code we'd inherited from Bob and hadn't had time to rewrite just yet, you see), and finally I came across:

class SomeRemoteAncestorOfMyClass : 
  public WendysClass {
  // ...
};

"Aha!" I exclaimed. "I didn't realize I was indirectly inheriting from yours, way up there in the hierarchy somewhere."

Wendy shrugged. "You shouldn't have to know about it, really. It was just a little mix-in. But, right, that was one of the ones I changed. But I didn't do much, just changed one line."

"Okay, so let's look at it." I pulled up Wendy's class's definition:

class WendysClass {
public:
  // ...
  virtual void Function( int mph );
};

"Seems innocuous," I started to say, but then we all stopped.

Wendy looked a little sideways at the screen. I thought something looked a little too familiar.

The Guru cleared her through to break through the silence. "Perhaps a diff?" she suggested. This time Wendy leaned forward and took the keyboard, and ran a quick diff, already knowing what she would find because she had just made the change. And sure enough:

- - - -Line  576 of 'WendysClass.cpp' - - - - 
- - -  void Function( int mph );
++++++++ Line  576 of 'WendysClass.cpp' ++++
+++ virtual void Function( int mph );
Files are different

"Oh," Wendy said in a small voice.

"Oh?" the Guru smiled.

"Oh!" I exclaimed, getting it. Finally. "So that's what was going on! My function wasn't virtual before, but suddenly it is because if the function already exists in a base class with the same name and signature, and it's virtual here, then it's good old 'once virtual, always virtual.' And instead of running my function's code, some further-derived class must have had a function with the same name and signature again—"

"Because we're pretty consistent about naming in this hierarchy," Wendy sighed, interrupting. "Bob wanted the names to be exactly the same wherever possible. Bad move."

"—and that became virtual, too, and hooked up to mine and got called instead. Nuts. I've been hijacked! No wonder the tests didn't do the right thing." Wendy shifted her weight a little, nervously. I sensed my opportunity: "You made my function virtual! How could you?" I mock chided, trying humor.

It seemed to work. Wendy smiled sheepishly. "You know," she shook her head, "I really should have thought of that. I guess changing the virtualness of a base class function is a breaking change. I—well, I guess I should say sorry. But you really shouldn't have called me a daughter of a—"

"Right, right, I'm sorry about that, too," I briskly interrupted her as the Guru lifted an interested eyebrow, "and now off to fix the problem. Say, you're right, there's sort of a similar kind of problem when it goes the other way—if you'd made it virtual to start, and then made it nonvirtual, then my function would have become nonvirtual and I would have had the opposite problem of not getting overrides called when I wanted them to be. Maybe it's better to be explicit when we want virtual. Still, it's too bad there isn't a nonvirtual keyword."

"Indeed," said the Guru. "Consider this parable." And she wrote:

class YourClass : public BaseClass {
public:
  // ...
  void Function();
};

"Is Function virtual?" she asked rhetorically. "As you see, maybe yes, maybe no. But consider the prophets Vandevoorde and Josuttis, in 1 Vandevoorde (also known as 2 Josuttis) chapter 16 verse 4." [1] She changed the code slightly:

template<typename BaseClass>
class YourClass : public BaseClass {
public:
  // ...
  void Function();
};

"Templates, as they write, let you parameterize much—including even the Virtuality of Functions. Is this blessing or bane? I know not which, but I think it is a sharp thing, this weapon, and best left sheathed." She put down the whiteboard marker and drifted off into thought.

"Okay, enough with the shtick," I said. "Bob's not around. I can force it to be virtual by writing virtual there explicitly, okay. But how do I force it not to be virtual? I guess I could push the Function into a helper base class and inherit from that, too..." I wrote:

class LeaveMeAlone {
public:
  void Function();
};
class MyClass : public LeaveMeAlone, public BaseClass {
public:
  // ...
};

"...but then it couldn't access the things in BaseClass. I know that's just not a practical solution in general. And I could rename it, breaking everyone who uses it, but it could still happen again later to the new name. So, how do I force it not to be virtual, practically?"

The Guru looked at me sadly, picked up her tome, and began to walk away.

"Huh? But I asked..." I trailed off as Wendy looked downcast, saddened, and started to leave as well. "But, look here, there has to be a way to make it not virtual..." I tried again, but all too quickly they were gone, and I sat quietly alone for a time in the dusty Monday afternoon silence.

References

[1] Vandevoorde, D. and N. Josuttis. C++ Templates, Addison-Wesley, 2003. See in particular section 16.4, "Parameterized Virtuality."


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.