Sealed classes and methods: Difference between revisions

m
Promoted to ‘full’ task
(C++ entry)
m (Promoted to ‘full’ task)
(5 intermediate revisions by 3 users not shown)
Line 1:
{{draft task}}
 
;Definition
In [[wp:Object-oriented_programming|object-oriented programming]], a '''sealed''' or '''final class''' is one which cannot be inherited from.
 
Classes are sometimes made non-subclasssablesubclassable in this way if the author feels that it would not be useful or even undesirable for subclasses to be created from them. Moreover, in a compiled language, knowing that a class cannot be subclassed, may enable optimizations to be made.
 
Rather than sealing the entire class, it may be possible to just seal certain 'public' methods for the same reasons and with the same potential benefits. 'private' methods should be effectively sealed anyway.
 
;Task
Line 84:
public:
explicit MovieWatcher(std::string_view name) : m_name{name}{}
virtual void WatchMovie() = 0; // must be overridden by derived classes
virtual void WatchMovie() override
{
std::cout << m_name << " likesis watching the movie\n";
}
virtual void EatPopcorn()
{
Line 97 ⟶ 102:
public:
explicit ParentMovieWatcher(std::string_view name) : MovieWatcher{name} {}
};
 
// ChildMovieWatcher can be inherited from
class ChildMovieWatcher : public MovieWatcher
{
public:
explicit ChildMovieWatcher(std::string_view name)
: MovieWatcher{name}{}
// EatPopcorn() cannot be overridden because it is 'final'
void WatchMovie() override
void EatPopcorn() final override
{
std::cout << m_name << " is watchingeating thetoo movie...much popcorn\n";
}
};
 
class YoungChildMovieWatcher : public ChildMovieWatcher
// ChildMovieWatcher can be inherited from
class ChildMovieWatcher : public MovieWatcher
{
int m_age;
public:
ChildMovieWatcherexplicit YoungChildMovieWatcher(std::string_view name, int age)
: MovieWatcherChildMovieWatcher{name}, m_age{age}{}
// WatchMovie() cannot be overridden because it is 'final'
void WatchMovie() final override
{
ifstd::cout (m_age<< "Sorry, " << 15)m_name <<
std::cout << "Sorry, " << m_name <<
", you are too young to watch the movie.\n";
else
std::cout << m_name << " likes the movie\n";
}
void EatPopcorn() override
{
if (m_age < 15)
std::cout << m_name << " is eating popcorn in the lobby\n";
else
std::cout << m_name << " is eating too much popcorn\n";
}
};
Line 133 ⟶ 134:
int main()
{
// A container for the MovieWatcher base class objects
std::vector<std::unique_ptr<MovieWatcher>> movieWatchers;
// Add some movie wathcers
movieWatchers.emplace_back(new ParentMovieWatcher("Donald"));
movieWatchers.emplace_back(new ChildMovieWatcher("Lisa", 18));
movieWatchers.emplace_back(new ChildMovieWatcherYoungChildMovieWatcher("Fred", 10));
 
// Send them to the movies
Line 151 ⟶ 155:
{{out}}
<pre>
Donald is watching the movie...
Lisa likesis watching the movie
Sorry, Fred, you are too young to watch the movie.
Donald is enjoying the popcorn
Lisa is eating too much popcorn
Fred is eating popcorntoo inmuch the lobbypopcorn
</pre>
 
Line 364 ⟶ 368:
<!--</syntaxhighlight>-->
Note however in Phix there is no possibility of invoking parent.watch_movie() from the else branch, because you have completely replaced that routine in the child instance. Should you want to share code in that kind of fashion you would need to give it a different and completely unambiguous name.
 
=={{header|Raku}}==
Raku doesn't have final class but [https://docs.raku.org/syntax/role Roles] is normally used to mimic the goal.
<syntaxhighlight lang="raku" line># 20240626 Raku programming solution
 
role MovieWatcherRole { has Str $.name;
method WatchMovie() { say "$.name is watching the movie" }
method EatPopcorn() { say "$.name is enjoying the popcorn" }
}
 
class MovieWatcher does MovieWatcherRole {
method new(Str $name) { self.bless(:$name) }
}
 
class ParentMovieWatcher is MovieWatcher {
method new(Str $name) { self.bless(:$name) }
}
 
role ChildMovieWatcherRole {
method EatPopcorn() { say "$.name is eating too much popcorn" }
}
 
class ChildMovieWatcher is MovieWatcher does ChildMovieWatcherRole {
method new(Str $name) { self.bless(:$name) }
}
 
role YoungChildMovieWatcherRole {
method WatchMovie() {
say "Sorry, $.name, you are too young to watch the movie.";
}
}
 
class YoungChildMovieWatcher is ChildMovieWatcher does YoungChildMovieWatcherRole {
method new(Str $name) { self.bless(:$name) }
}
 
for ParentMovieWatcher.new('Donald'),
ChildMovieWatcher.new('Lisa'),
YoungChildMovieWatcher.new('Fred')
{ .WatchMovie and .EatPopcorn }</syntaxhighlight>
 
You may [https://ato.pxeger.com/run?1=nVPBToNAED144ysmxKRtgpyNPVo9adLYg_G4wlBQ2Gl2FxvS8CVeetCf8uKvuLtAoIVIldNm9r15bx6z7x-Cveb7_WeuoovLr7NvQSnCPb0l-MhUEKN4MIUdxEzCSgk49znLcO4AQIYqphAszjKmMw2UrAC3QkEiYWtuE74GFSNkBuVqatnh3zC1pE1Agg_xkb9Q0fA3Fc7V_NJxgpRJeeAVQkI54L6jxnE7tXMYAauHaeQ_pyjl9KoudrovmUCuDjSSI81_dbcxX8dJGv7qdiQbpmwyRJDlQTwYT0-j599mNm7lb6M9Uc7X402Pdsfc6M-OuSIhCq_eNw8KykH_CztsYZrrU7Vc7Wb57ty26Iw_7MNk0C_aIE40fnIaEYmBJfINf7IgztJwMvPs3D3RCnSXSNZAhs1VuFuBupWzA78NFRgPwW-XCMrqndfPvXn2Pw Attempt This Online!]
 
=={{header|Wren}}==
Line 379 ⟶ 425:
 
3. Using the 'is' operator (i.e. a ''is'' C) to detect the type of 'a' wouldn't work here as this would return 'true' if 'a' were either a 'C' object or an object of a subclass of 'C'. It is possible to spoof the 'is' operator by overriding its normal behavior, though this is definitely not recommended!
<syntaxhighlight lang="ecmascriptwren">class Parent {
construct new(name, age) {
_name = name
9,490

edits