7

I have

class Rect{
   // stuff
};

and

class SpecialRect:public Rect{
private:
     operator const Rect(){return *this;}          // No implicits casts to Rect
public:
     // stuff
};

SpecialRect inherits all the properties and methods from Rect except that I want to avoid non-explicit conversions of SpecialRect to the base class Rect.

In the code

SpecialRect oneSpecial;
Rect aRect=oneSpecial;          // I want this to not compile. (to remind-me to declare aRect as SpecialTect)

Compiles with no errors. (I know that declaring the base class Rect as private would do it but I don't want to reimplement all its methods.)

Is there a way to achieve this?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
tru7
  • 6,348
  • 5
  • 35
  • 59
  • 4
    it's basically like asking "How do I prevent my cat from being an Animal", why would you want to prevent that? seems like broken design – David Haim Apr 07 '16 at 10:27
  • 2
    You violating the old 'is a' rule: Your special rectangle is no rectangle. –  Apr 07 '16 at 10:28
  • You might want to have a look at the [Liskov Substitution Principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle). – TartanLlama Apr 07 '16 at 10:30
  • 3
    @DavidHaim: As stated, OP want to disallow object **slicing**. – Jarod42 Apr 07 '16 at 10:40
  • Thanks @Jarod42, I didn't know the "object slicing" concept. This may help to look further. – tru7 Apr 07 '16 at 10:43
  • @Jarod42 he didn't specify it when the question was first published. – David Haim Apr 07 '16 at 10:43
  • BTW, since c++11, `=delete;` is better to forbid than `private` without implementation (even if you wrongly provide one). – Jarod42 Apr 07 '16 at 12:23

1 Answers1

7

Declaring private copy constructor of SpecialRect in Rect will do the trick but with one disadvantage: Rect depends on SpecialRect declaration. [from Jarod42's comment]

Note: Remember you need to implement the empty constructor because there will not be default constructor.

class SpecialRect;

class Rect {
public:
    Rect(){}

private:
    Rect(const SpecialRect&);
    //Rect(const SpecialRect&) = delete; // c++11
};

class SpecialRect : public Rect {

};


int main()
{
    SpecialRect sr;
    //Rect r1 = sr; // error: 'Rect::Rect(const SpecialRect&)' is private
    //Rect r2(sr); // error: 'Rect::Rect(const SpecialRect&)' is private

    Rect r3;
    Rect r4(r3);
    Rect r5 = r3;
    return 0;
}

Another solution is to declare explicit default copy constructor in Rect. This has the benefit of not depending on sub classes but has side effects.

class Rect {
public:
    Rect(){}
    explicit Rect(const Rect&);
};

class SpecialRect : public Rect {

};

int main()
{
    SpecialRect sr;
    //Rect r1 = sr; // Prevents this
    Rect r2(sr);    // Leaves this

    Rect r3;
    Rect r4(r3);
    //Rect r5 = r3;  // Side Effect: Prevents this

    return 0;
}
Meena Alfons
  • 1,230
  • 2
  • 13
  • 30
  • 3
    But `Rect r(sr)` still works. `Rect(const SpecialRect&) = delete;` is an alternative. – Jarod42 Apr 07 '16 at 10:38
  • You are right, I noticed that and was working on another solution – Meena Alfons Apr 07 '16 at 10:47
  • 2
    With c++11, `=delete;` is better than old c++03 `private` without implementation. – Jarod42 Apr 07 '16 at 12:18
  • 1
    First answer with `explicit` copy constructor has its advantage: simple without dependency on SubClass. – Jarod42 Apr 07 '16 at 12:20
  • The explicit copy constructor worked very well in my case and the side effects are apparently positive (enforce some more discipline :-) – tru7 Apr 07 '16 at 14:35
  • 1
    But you still can CAST to Rect, in both cases! `Rect& rect = static_cast(sr);` Proof 1 : http://coliru.stacked-crooked.com/a/449d533279215d62 . Proof 2 : http://coliru.stacked-crooked.com/a/3f909a9df3cf9a78 – tower120 Jun 12 '18 at 14:15
  • 1
    The title of the question is misleading. What @Joan described in his question is that he need to prevent copying a derived object to a base object. That's what the answer is about. – Meena Alfons Jun 16 '18 at 16:25