0

I have the following design problem:
I have a Resource with two sorts of accessors:

  • one is to modify it (let's call it Access)
  • one is for const-like access (let's call it Const_access), but you could say c1=c2 and then c1 will access c2.

Given that Resource is big, I have to achieve the following copy mechanism:

Access->Access:             deep copy
Access->Const_access:       deep copy
Const_access->Access:       deep copy
Const_access->Const_access: shallow copy

I aim to write Access so that Const_access will be able to use exactly the const functions in Access. My current implementation is flawed, using:

class Access {
  public:
  Access(const Access&); // deep copy
  void method(const Access&); 
  void const_method() const; 
  protected: 
  Resource res;
};
class Const_access : public Access{
  private:
  void method(); // only declaration
  public:
  Const_access(const Const_accesss&); // shallow copy
  explicit Const_access(const Access&); // deep copy
};

but here Const_access ca; ca.Access::method() still works and I have to manually hide away the non-const accessors. I have tried protected or private inheritance but that prohibits flexibility for Access& to handle Const_Access& too.

What would be the correct solution for this problem?

Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
  • possible duplicate of [Can I write different copyCtor for const and non-const instances?](http://stackoverflow.com/questions/13343718/can-i-write-different-copyctor-for-const-and-non-const-instances) – R. Martinho Fernandes Nov 12 '12 at 12:32
  • 2
    Since the contract of `Const_Access` is narrower than that of `Access`, the inheritance as stated makes no sense. A `Const_Access` cannot be used in place of an `Access`, so it would be a violation of the Liskov substitution principle. – David Rodríguez - dribeas Nov 12 '12 at 12:42
  • I don't think this is duplicate question because of the added kink of violating the Liskov substitution principle. – David Hammen Nov 12 '12 at 12:46

3 Answers3

2

What you are saying is contradictory.

On the one hand, you want to disallow things like:

Const_access foo;
foo.modify();

but on the other hand, you do want to allow things like:

void bar(Access& a) {
    a.modify();
}

Const_access foo;
bar(foo);

This does not make sense.

A more logical relationship is to turn the inheritence structure around:

class Const_access {
public:
    Const_access(const Const_access&); // shallow copy
    void const_method() const;
protected:
    Resource res; // or perhaps a reference-counted pointer?
};

class Access: public Const_access {
public:
    Access(const Access&); // deep copy
    explicit Access(const Const_access&); // deep copy
    void method();
};

The only thing it does not give is a deep-copy when converting an Access to a Const_access.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
  • Yes, this would be the normal solution but as you wrote it does not give deep copy on `Access` to `Const_access`. And this was my reason to come up with an upside-down nasty looking stuff in the question. :( So complicated :( – Barney Szabolcs Nov 12 '12 at 15:54
0

Your function method() has public visibility in the base class but is private in the derived class. This violates the Liskov substitution principle. A derived class should extend rather than contract the base class.

The solution is to not violate that principle. For example, make the inheritance in class Const_access private or protected, or provide an implementation method() in class Const_access.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
0

This problem can simply solved using so called lazy evaluation:
making the private clone of the class resources only when a member function wants to modify it. R/W and Read-only access to resources is easily solved with private inheritance.

This way also the LSP is abided: Obj is now flawlessly publicly inherited from Const_obj, if necessary at all.
There is a link for the complete answer.

Community
  • 1
  • 1
Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91