Why does C++ forbid private inheritance of a final class?
C++11 introduced the final
keyword to C++.
It can be used on a virtual method or on a class.
Declaring a class final forbids any kind of inheritance: public, protected and private.
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
While it can be reasonable to forbid public inheritance (e.g. if my class doesn't have a virtual destructor, or for other reasons), why should I forbid private inheritance?
Might it be that if final
forbade only public inheritance, that std::string
and its other friends in std would have been final
-- as they should -- for not having a virtual destructor?
EDIT:
Howard Hinnant already answered Why the standard containers are not final but still, there is a reason for declaring a class final but allowing private inheritance.
c++ final
add a comment |
C++11 introduced the final
keyword to C++.
It can be used on a virtual method or on a class.
Declaring a class final forbids any kind of inheritance: public, protected and private.
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
While it can be reasonable to forbid public inheritance (e.g. if my class doesn't have a virtual destructor, or for other reasons), why should I forbid private inheritance?
Might it be that if final
forbade only public inheritance, that std::string
and its other friends in std would have been final
-- as they should -- for not having a virtual destructor?
EDIT:
Howard Hinnant already answered Why the standard containers are not final but still, there is a reason for declaring a class final but allowing private inheritance.
c++ final
8
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for makingstd::string
and most of other library classesfinal
.
– VTT
Dec 25 '18 at 8:14
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22
add a comment |
C++11 introduced the final
keyword to C++.
It can be used on a virtual method or on a class.
Declaring a class final forbids any kind of inheritance: public, protected and private.
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
While it can be reasonable to forbid public inheritance (e.g. if my class doesn't have a virtual destructor, or for other reasons), why should I forbid private inheritance?
Might it be that if final
forbade only public inheritance, that std::string
and its other friends in std would have been final
-- as they should -- for not having a virtual destructor?
EDIT:
Howard Hinnant already answered Why the standard containers are not final but still, there is a reason for declaring a class final but allowing private inheritance.
c++ final
C++11 introduced the final
keyword to C++.
It can be used on a virtual method or on a class.
Declaring a class final forbids any kind of inheritance: public, protected and private.
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
While it can be reasonable to forbid public inheritance (e.g. if my class doesn't have a virtual destructor, or for other reasons), why should I forbid private inheritance?
Might it be that if final
forbade only public inheritance, that std::string
and its other friends in std would have been final
-- as they should -- for not having a virtual destructor?
EDIT:
Howard Hinnant already answered Why the standard containers are not final but still, there is a reason for declaring a class final but allowing private inheritance.
c++ final
c++ final
edited Dec 25 '18 at 12:22
Boann
37.2k1290121
37.2k1290121
asked Dec 25 '18 at 8:05
Amir KirshAmir Kirsh
1,368920
1,368920
8
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for makingstd::string
and most of other library classesfinal
.
– VTT
Dec 25 '18 at 8:14
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22
add a comment |
8
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for makingstd::string
and most of other library classesfinal
.
– VTT
Dec 25 '18 at 8:14
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22
8
8
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for making
std::string
and most of other library classes final
.– VTT
Dec 25 '18 at 8:14
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for making
std::string
and most of other library classes final
.– VTT
Dec 25 '18 at 8:14
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22
add a comment |
2 Answers
2
active
oldest
votes
Inheritance is inheritance. Accessibility is orthogonal to it. It only protects from statically treating the derived class as the base, outside the scope of the derived class. It makes no difference at runtime, and if private inheritance was allowed, you could write this:
struct C {
virtual void foo() {}
};
struct A final : C {
virtual void foo() {}
};
void baz(A& ref) { ref.foo(); }
class B: private A {
virtual void foo() {}
void bar() {
baz(*this);
}
};
Private inheritance doesn't stop you from using run-time polymorphism. If final
is meant to fully prevent further overriding, then private inheritance must be included in the prohibition.
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to havefinal
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.
– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
add a comment |
In addition to what Story Teller said, consider the reason for introducing final
: It's supposed to help optimizations.
When a class is final
, and you have a pointer to it, the compiler can prove which member function you are calling, even if it's virtual
. If the class is not final
, the pointer could actually be a pointer to some derived class, which could conceivably override the virtual
method, forcing a full dynamic vtable lookup.
Whether the inheritance is private
or not, it is always possible to create a base-class pointer. In the case of private
inheritance, the creation of this base-class pointer would be restricted to the deriving class, the derived class, and any base of the derived class, which is still more code than the optimizer has available to make its decisions. As such, only forbidding all inheritance allows the virtual call optimizations to be made.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53920492%2fwhy-does-c-forbid-private-inheritance-of-a-final-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Inheritance is inheritance. Accessibility is orthogonal to it. It only protects from statically treating the derived class as the base, outside the scope of the derived class. It makes no difference at runtime, and if private inheritance was allowed, you could write this:
struct C {
virtual void foo() {}
};
struct A final : C {
virtual void foo() {}
};
void baz(A& ref) { ref.foo(); }
class B: private A {
virtual void foo() {}
void bar() {
baz(*this);
}
};
Private inheritance doesn't stop you from using run-time polymorphism. If final
is meant to fully prevent further overriding, then private inheritance must be included in the prohibition.
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to havefinal
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.
– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
add a comment |
Inheritance is inheritance. Accessibility is orthogonal to it. It only protects from statically treating the derived class as the base, outside the scope of the derived class. It makes no difference at runtime, and if private inheritance was allowed, you could write this:
struct C {
virtual void foo() {}
};
struct A final : C {
virtual void foo() {}
};
void baz(A& ref) { ref.foo(); }
class B: private A {
virtual void foo() {}
void bar() {
baz(*this);
}
};
Private inheritance doesn't stop you from using run-time polymorphism. If final
is meant to fully prevent further overriding, then private inheritance must be included in the prohibition.
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to havefinal
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.
– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
add a comment |
Inheritance is inheritance. Accessibility is orthogonal to it. It only protects from statically treating the derived class as the base, outside the scope of the derived class. It makes no difference at runtime, and if private inheritance was allowed, you could write this:
struct C {
virtual void foo() {}
};
struct A final : C {
virtual void foo() {}
};
void baz(A& ref) { ref.foo(); }
class B: private A {
virtual void foo() {}
void bar() {
baz(*this);
}
};
Private inheritance doesn't stop you from using run-time polymorphism. If final
is meant to fully prevent further overriding, then private inheritance must be included in the prohibition.
Inheritance is inheritance. Accessibility is orthogonal to it. It only protects from statically treating the derived class as the base, outside the scope of the derived class. It makes no difference at runtime, and if private inheritance was allowed, you could write this:
struct C {
virtual void foo() {}
};
struct A final : C {
virtual void foo() {}
};
void baz(A& ref) { ref.foo(); }
class B: private A {
virtual void foo() {}
void bar() {
baz(*this);
}
};
Private inheritance doesn't stop you from using run-time polymorphism. If final
is meant to fully prevent further overriding, then private inheritance must be included in the prohibition.
edited Dec 25 '18 at 12:24
Boann
37.2k1290121
37.2k1290121
answered Dec 25 '18 at 8:12
StoryTellerStoryTeller
101k12206274
101k12206274
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to havefinal
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.
– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
add a comment |
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to havefinal
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.
– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
Beautiful example, which reminds me the peculiar rule: if B is privately inherited from A, object of type B is still considered "an A" inside B itself! IMHO it would be better if the spec would not allow B in this case (of private inheritance) to override private virtuals of A, even without final! But this would be an extra rule for a very rare case I guess... and maybe not a good one at all. A better rule might be: be careful with private inheritance.
– Amir Kirsh
Dec 25 '18 at 8:42
1
1
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
@AmirKirsh - A subsection of the master rule. Be careful with C++ in general :)
– StoryTeller
Dec 25 '18 at 8:43
2
2
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
privately inherited from the master rule? :-)
– Amir Kirsh
Dec 25 '18 at 8:49
It could have been possible to have
final
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.– Deduplicator
Dec 25 '18 at 12:36
It could have been possible to have
final
only cap the polymorphic hierarchy. In that case, accessibility wouldn't have come into it either though.– Deduplicator
Dec 25 '18 at 12:36
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
@Deduplicator - Could have. But the paper proposing it wanted to give class authors the tool to say "you can't inherit from this, period". That's not without merit either, and that's the direction the committee went with.
– StoryTeller
Dec 25 '18 at 12:41
add a comment |
In addition to what Story Teller said, consider the reason for introducing final
: It's supposed to help optimizations.
When a class is final
, and you have a pointer to it, the compiler can prove which member function you are calling, even if it's virtual
. If the class is not final
, the pointer could actually be a pointer to some derived class, which could conceivably override the virtual
method, forcing a full dynamic vtable lookup.
Whether the inheritance is private
or not, it is always possible to create a base-class pointer. In the case of private
inheritance, the creation of this base-class pointer would be restricted to the deriving class, the derived class, and any base of the derived class, which is still more code than the optimizer has available to make its decisions. As such, only forbidding all inheritance allows the virtual call optimizations to be made.
add a comment |
In addition to what Story Teller said, consider the reason for introducing final
: It's supposed to help optimizations.
When a class is final
, and you have a pointer to it, the compiler can prove which member function you are calling, even if it's virtual
. If the class is not final
, the pointer could actually be a pointer to some derived class, which could conceivably override the virtual
method, forcing a full dynamic vtable lookup.
Whether the inheritance is private
or not, it is always possible to create a base-class pointer. In the case of private
inheritance, the creation of this base-class pointer would be restricted to the deriving class, the derived class, and any base of the derived class, which is still more code than the optimizer has available to make its decisions. As such, only forbidding all inheritance allows the virtual call optimizations to be made.
add a comment |
In addition to what Story Teller said, consider the reason for introducing final
: It's supposed to help optimizations.
When a class is final
, and you have a pointer to it, the compiler can prove which member function you are calling, even if it's virtual
. If the class is not final
, the pointer could actually be a pointer to some derived class, which could conceivably override the virtual
method, forcing a full dynamic vtable lookup.
Whether the inheritance is private
or not, it is always possible to create a base-class pointer. In the case of private
inheritance, the creation of this base-class pointer would be restricted to the deriving class, the derived class, and any base of the derived class, which is still more code than the optimizer has available to make its decisions. As such, only forbidding all inheritance allows the virtual call optimizations to be made.
In addition to what Story Teller said, consider the reason for introducing final
: It's supposed to help optimizations.
When a class is final
, and you have a pointer to it, the compiler can prove which member function you are calling, even if it's virtual
. If the class is not final
, the pointer could actually be a pointer to some derived class, which could conceivably override the virtual
method, forcing a full dynamic vtable lookup.
Whether the inheritance is private
or not, it is always possible to create a base-class pointer. In the case of private
inheritance, the creation of this base-class pointer would be restricted to the deriving class, the derived class, and any base of the derived class, which is still more code than the optimizer has available to make its decisions. As such, only forbidding all inheritance allows the virtual call optimizations to be made.
answered Dec 25 '18 at 12:46
cmastercmaster
26.2k63982
26.2k63982
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53920492%2fwhy-does-c-forbid-private-inheritance-of-a-final-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
8
Not having a virtual destructor does not prohibit or limit inheritance anyhow. It only makes ownership over object through a pointer to base class faulty. So that is not a reason for making
std::string
and most of other library classesfinal
.– VTT
Dec 25 '18 at 8:14
How would that hypothetical feature work? Assume you can derive (if only privately) from a final class. Would virtual functions be treated as final?
– curiousguy
Dec 25 '18 at 14:22