Idiomatic way to prevent slicing? The 2019 Stack Overflow Developer Survey Results Are InForce...
What is the steepest angle that a canal can be traversable without locks?
Can I write a for loop that iterates over both collections and arrays?
Why Did Howard Stark Use All The Vibranium They Had On A Prototype Shield?
Should I use my personal or workplace e-mail when registering to external websites for work purpose?
Output the Arecibo Message
If Wish Duplicates Simulacrum, Are Existing Duplicates Destroyed?
Extreme, unacceptable situation and I can't attend work tomorrow morning
Falsification in Math vs Science
Polarization lost upon 2nd reflection?
The difference between dialogue marks
Could JWST stay at L2 "forever"?
Is this food a bread or a loaf?
Which Sci-Fi work first showed weapon of galactic-scale mass destruction?
A poker game description that does not feel gimmicky
Inline version of a function returns different value then non-inline version
How to deal with fear of taking dependencies
How long do I have to send payment?
How to answer pointed "are you quitting" questioning when I don't want them to suspect
Where does the "burst of radiance" from Holy Weapon originate?
Inversion Puzzle
In microwave frequencies, do you use a circulator when you need a (near) perfect diode?
Families of ordered set partitions with disjoint blocks
Why don't Unix/Linux systems traverse through directories until they find the required version of a linked library?
Does light intensity oscillate really fast since it is a wave?
Idiomatic way to prevent slicing?
The 2019 Stack Overflow Developer Survey Results Are InForce function to be called only with specific typesWhat's the best way to trim std::string?What is object slicing?What's the point of g++ -Wreorder?Easiest way to convert int to string in C++Does the C++ spec allow an instance of a non-virtual class to include memory for a vtable pointer?capture variables inside of subclass?Detecting if a type can be derived from in C++C++ overload function by return typeIs using inline classes inside a function permitted to be used as template types?Short-circuit evaluation and assignment in C++
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Sometimes it can be an annoyance that c++ defaults to allow slicing. For example
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
foo y = x; // <- I dont want this to compile!
}
This compiles and runs as expected! Though, what if I dont want to enable slicing?
What is the idomatic way to write foo such that one cannot slice instances of any derived class?
c++ inheritance object-slicing
add a comment |
Sometimes it can be an annoyance that c++ defaults to allow slicing. For example
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
foo y = x; // <- I dont want this to compile!
}
This compiles and runs as expected! Though, what if I dont want to enable slicing?
What is the idomatic way to write foo such that one cannot slice instances of any derived class?
c++ inheritance object-slicing
add a comment |
Sometimes it can be an annoyance that c++ defaults to allow slicing. For example
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
foo y = x; // <- I dont want this to compile!
}
This compiles and runs as expected! Though, what if I dont want to enable slicing?
What is the idomatic way to write foo such that one cannot slice instances of any derived class?
c++ inheritance object-slicing
Sometimes it can be an annoyance that c++ defaults to allow slicing. For example
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
foo y = x; // <- I dont want this to compile!
}
This compiles and runs as expected! Though, what if I dont want to enable slicing?
What is the idomatic way to write foo such that one cannot slice instances of any derived class?
c++ inheritance object-slicing
c++ inheritance object-slicing
edited 29 mins ago
rrauenza
3,55921835
3,55921835
asked 3 hours ago
user463035818user463035818
18.7k42970
18.7k42970
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.
– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
|
show 2 more comments
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};
3
but then I cannot copyfoos anymore :( I'd like to prevent only copying a bar to a foo if possible
– user463035818
3 hours ago
add a comment |
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
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%2f55600025%2fidiomatic-way-to-prevent-slicing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.
– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
|
show 2 more comments
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.
– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
|
show 2 more comments
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
edited 3 hours ago
answered 3 hours ago
NathanOliverNathanOliver
98.5k16138218
98.5k16138218
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.
– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
|
show 2 more comments
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.
– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
If I'm not mistaken, the default copy constructor is not necessary.
– geza
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
@geza Yep. I'd need it if i had added the move operators but removing them gives me the defaults for them all. I've removed them. Thanks.
– NathanOliver
3 hours ago
Note that this doesn't prevent explicit slicing like this:
foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.– eerorika
3 hours ago
Note that this doesn't prevent explicit slicing like this:
foo y = static_cast<foo&>(x);. That said, perhaps it's not a problem to OP.– eerorika
3 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
if I understand correctly this is a nice way to prevent implicit conversions for function parameters in general
– user463035818
2 hours ago
1
1
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
I look at it as reverse SFINAE. You make the overloads you want to compile, and then add a deleted template stopping everything else.
– NathanOliver
2 hours ago
|
show 2 more comments
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};
3
but then I cannot copyfoos anymore :( I'd like to prevent only copying a bar to a foo if possible
– user463035818
3 hours ago
add a comment |
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};
3
but then I cannot copyfoos anymore :( I'd like to prevent only copying a bar to a foo if possible
– user463035818
3 hours ago
add a comment |
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};
answered 3 hours ago
eerorikaeerorika
89.8k664136
89.8k664136
3
but then I cannot copyfoos anymore :( I'd like to prevent only copying a bar to a foo if possible
– user463035818
3 hours ago
add a comment |
3
but then I cannot copyfoos anymore :( I'd like to prevent only copying a bar to a foo if possible
– user463035818
3 hours ago
3
3
but then I cannot copy
foos anymore :( I'd like to prevent only copying a bar to a foo if possible– user463035818
3 hours ago
but then I cannot copy
foos anymore :( I'd like to prevent only copying a bar to a foo if possible– user463035818
3 hours ago
add a comment |
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
add a comment |
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
add a comment |
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
answered 3 hours ago
Richard HodgesRichard Hodges
56.9k658105
56.9k658105
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%2f55600025%2fidiomatic-way-to-prevent-slicing%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