views:

65

answers:

3

Here is a complete example. I want to forbid using A::set from objects casted from B to A by allowing only casting B to const A. How to do it? (I can't use virtual functions)

#include <iostream>
#include <cassert>

using namespace std;

class A {
public:
  int  get() const { return i_; }
  void set(int i) { i_ = i; }
protected:
  int i_;
};

class B : public A {
public:
  int  ok() const { return A::get() == copy_i_; }
  void set(int i) { A::set(i); copy_i_ = i; }
protected:
  int copy_i_;
};

void test2() {
  A a;
  a.set(3); // ok here
  cout << a.get() << endl;

  B b;
  b.set(5);
  A& aa = b;
  assert(b.ok());
  aa.set(3); // not ok here
  assert(b.ok()); // fail-here
}

int main() {
  test2();
  return 0;
}
A: 

Why casting? Making void A::set(int i) protected will work in your case.

Abhay
But I want to modify pure A objects.
Łukasz Lew
A: 

There is no need for forbidding non-const casts. You can solve your problem by using the template method design pattern.

#include "stdafx.h"
#include <iostream>
#include <cassert>

using namespace std;

class A {
public:
  int  get() const { return i_; }
  void set(int i) { assert(i_ = i); copy_i();}

protected:
  int i_;
  virtual void copy_i(){};
};


class B : public A {
public:
  int  ok() const { return A::get() == copy_i_; }
protected:
  int copy_i_;
  void copy_i(){copy_i_ = i_; }
};

void test2() {
  B b;
  b.set(5);
  A& a = b;
  assert(b.ok());
  a.set(3);
  assert(b.ok()); // success!
}

int main() {
  test2();
  return 0;
}
Adrian Grigore
As I said, I can't use virtual functions due to performance reasons.And it would be nice If class A could be left unchanged.
Łukasz Lew
In this case I don't think it can be done. But have you actually profiled your application to ensure that virtual functions are too slow? The overhead for a virtual function is usually negligible.
Adrian Grigore
I did profile. virtual functions are too slow because they can't be inlined
Łukasz Lew
+2  A: 

You could make the inheritance private and provide a member function in B to use instead of casting.

const A& B::convert_to_A() const { return *this; }
James Hopkin
Exactly what I needed, Thanks.
Łukasz Lew