// Remove "x" to invoke feature.
#define xTEST_BAD_ASSIGN
#if defined( CPP11 )
# define OVERRIDE override
# define NOEXCEPT noexcept
#else
# define OVERRIDE
# define NOEXCEPT throw()
#endif
//---------------------------------------------------------------------------
#include <algorithm> // std::swap
#include <iostream> // std::wcout, std::endl
#include <string> // std::string
#include <utility> // std::forward
using namespace std;
#if defined( CPP11 )
template< class Base >
class Assignable_ final
: public Base
{
public:
using Base::Base;
using Base::operator=;
};
#else
template< class Base >
class Assignable_;
class IsFinalAssignable
{
template< class > friend class Assignable_;
private:
IsFinalAssignable() {}
};
template< class Base >
class Assignable_
: private virtual IsFinalAssignable
, public Base
{
public:
Assignable_(): Base() {}
template< class Arg1 >
Assignable_( Arg1 const& a1 )
: Base( a1 )
{}
template< class Arg1, class Arg2 >
Assignable_( Arg1 const& a1, Arg2 const& a2 )
: Base( a1, a2 )
{}
using Base::operator=;
};
#endif
class Person
{
private:
string name_;
protected:
void swapWith( Person& other ) NOEXCEPT
{
swap( name_, other.name_ );
}
void operator=( Person other ) { swapWith( other ); }
public:
typedef Assignable_<Person> Assignable;
string name() const { return name_; }
Person( string const& name )
: name_( name )
{}
};
class Student
: public Person
{
private:
int studentId_;
protected:
void swapWith( Student& other ) NOEXCEPT
{
Person::swapWith( other );
swap( studentId_, other.studentId_ );
}
void operator=( Student other ) { swapWith( other ); }
public:
typedef Assignable_<Student> Assignable;
int studentId() const { return studentId_; }
Student( string const& name, int const studentId )
: Person( name ), studentId_( studentId )
{}
};
#ifdef TEST_EXTENSION
class Extension
: public Person::Assignable
{
public:
Extension(): Person::Assignable( "Somebody" ) {}
};
#endif
wostream& operator<<( wostream& stream, string const& s )
{
return (stream << s.c_str());
}
int main()
{
Person::Assignable a( "Hillary Clinton" );
Student::Assignable b1( "John Smith", 12345 );
Student b2( "Mary Jones", 88888 );
Person& bAsPerson = b1; // OK.
wcout
<< "Name: " << b1.name()
<< ". Student id: " << b1.studentId() << "."
<< endl;
#ifdef TEST_BAD_ASSIGN
bAsPerson = a; // Does not compile. :-)
#else
b1 = b2; // Good/allowed assignment.
#endif
wcout
<< "Name: " << b1.name()
<< ". Student id: " << b1.studentId() << "."
<< endl;
}