Giving derived class only const access to base class data members/functions - c++

In my specific case, I have a base class 'Base', with a data member 'A_var'. I'd like that any derived classes only have const access to that data member, in a syntactically equal fashion to the 'Base' class.
If it's protected or private, then derived classes have full or no access, respectively. I could make it private, and make a protected function that returns a const reference, but then the access would be syntactically different.
class Base {
protected:
const type_t& A() const {return A_var;}
private:
type_t A_var;
void f();
};
class Derived : public Base{
public:
void g();
};
//access in Base class
void Base::f() {
type_t value = A_var;
A_var = value;
}
//access in Derived class
void Derived::g() {
type_t value = A();
A() = value; //Error, const reference; good
}
Overloading 'A()', as below, also doesn't work, because the 'Derived' class calls the private non-const 'A()'.
protected:
const type_t& A() const {return A_var;}
private:
type_t& A() {return A_var;}
The small difference may not seem like a big deal, but in my code there are various macros that start with access to that data member. As such, I have to have different macros for the 'Base' class and derived classes, which disrupts the flow of the code, both reading and writing.
Update:
To clarify, the issue is one of making the access in the derived and base classes the same, syntactically. That is, for instance, that I could call a function f(), and have it return a non-const reference when called in the base class, but a const reference when called in a derived class. The motivation is to make the forced const access in derived classes seamless. I realize there may not be a way to do this, but I asked just in case.
Update:
To present a real example (there are 2-3 of such cases), this is used a lot in the code:
test_files_var.current()->current_test()
I replaced that with a
#define TEST() test_files_var.current()->current_test()
because the derived class would access test_files_var through a different function/member, i.e. testFiles(), I have to have a second definition of TEST(), i.e. DTEST(). The problem is given more by the number of times the 'macros' are used, than by how many of them there are.

Where is no simple built-in solution.
But a bit of template magic can probably do a trick:
template <class NonConst>
struct Matcher {
template <class AnyOther>
static const AnyOther &get(AnyOther &obj) { return obj; }
static NonConst &get(NonConst &obj) { return obj; }
};
class Base {
public:
Base() : a_(42) { }
public:
virtual void Fun() {
Matcher<Base>::get(*this).A();
}
const int &A() const {
std::cout << "const" << std::endl;
return a_;
}
int &A() {
std::cout << "no const" << std::endl;
return a_;
}
private:
int a_;
};
class Derived : public Base {
public:
void Fun() {
Matcher<Base>::get(*this).A();
}
};
int main(int argc, const char * argv[]) {
Derived d;
d.Fun();
Base b;
b.Fun();
return 0;
}
The code above will output: const no const.
So in both Fun functions you have essentially the same access pattern which you could wrap in a macros if you need.

If I understand your question correctly, you want to give access to the derived classes access to a private variable of the base class but in read only.
In this case, you just have to define a protected constant reference variable and intialize it to the private variable:
class Base {
public:
Base() : cA(A_var) { ... } // to be completed with rule of 3
protected:
const type_t& cA;
private:
type_t A_var;
void f();
};
The access in the derived class uses then the constant reference:
//access in Derived class
void Derived::g() {
type_t value = cA;
//cA = value; //Error, const reference: can't assign
}
Live demo

You may change your Base class to
class Base {
public:
Base() : A_cref(A_var) {}
private:
type_t A_var;
void f();
protected:
const type_t& A_cref;
};
with the extra member overhead.

If the macros are usable from the derived classes, they can only need const access - so the macros can use the protected const access function.
Macros that are going to modify the variable will have to use the private variable, and will only be usable in the base class.

It appears that you problems will go away if you replace your TEST() macro with the public function test() in the base class:
class Base
{
public:
void test() { test_files_var.current()->current_test() }
private:
type_t test_files_var;
};

Related

How to use derived parameter in an overriding function without dynamic casting

Can anyone let me know how to achieve:
the parameter of a method of a derived class being the parameter's
derived class (not the parameter's base class)?
This is what I want:
class Base{
public:
// Base class method has ParameterBase parameter
virtual void f(ParameterBase pb) = 0;
}
class Derived : public Base{
public:
// I want: Derived class method has ParameterDerived parameter;
void f(ParameterDerived pd){ //do something with pd; }
}
class ParameterBase{
// Base class of parameter;
}
class ParameterDerived : public ParameterBase{
// Derived class of parameter;
}
How to achieve above?
Do I have to use ParamterBase in the derived method's parameter list and dynamic_cast the parameter in the method body?
The feature you are asking for is called parameter type contra-variance. And C++ unfortunately, doesn't support it. C++ supports just the return type covariance. See here for a nice explanation.
Perhaps inconveniently, C++ does not permit us to write the function
marked hmm... above. C++’s classical OOP system supports “covariant
return types,” but it does not support “contravariant parameter
types.”
But you can use dynamic_cast<>() operator. But first, you must change the parameter type to pointer or reference, and add at least one virtual member (virtual destructor counts too) to your class ParameterBase to make compiler to create virtual method table for it. Here is the code with references. Pointers can be used instead.
class ParameterBase
{
public:
// To make compiler to create virtual method table.
virtual ~ParameterBase()
{}
};
class ParameterDerived : public ParameterBase
{
};
class Base
{
public:
// Pointers or references should be used here.
virtual void f(const ParameterBase& pb) = 0;
};
class Derived : public Base
{
public:
virtual void f(const ParameterBase& pb) override
{
// And here is the casting.
const ParameterDerived& pd=dynamic_cast<const ParameterDerived&>(pb);
}
};
int main()
{
Derived d;
ParameterDerived p;
d.f(p);
}
Supposing you want Derived to be called with ParameterDerived, but you also want to declare the interface in abstract base classes.
The interface MUST have the same parameter types, but you can still enforce the right parameter subclass with a dynamic_cast inside Derived::f
#include <iostream>
#include <string>
// interface
struct ParameterBase {
virtual ~ParameterBase() {};
};
struct Base {
virtual void f(ParameterBase *pb) = 0;
virtual ~Base() {};
};
// specific
struct ParameterDerived : public ParameterBase {
std::string name;
ParameterDerived(const std::string &name) : name(name) {}
ParameterDerived& operator=(const ParameterDerived& rhs) { name = rhs.name; }
~ParameterDerived() {};
};
struct Derived : public Base {
Derived(){}
Derived& operator=(const Derived &rhs) {}
virtual ~Derived(){}
void f(ParameterBase *pb) {
ParameterDerived *pd = dynamic_cast<ParameterDerived*>(pb);
if (pd) {
std::cout << "Derived object with derived parameter " << pd->name << std::endl;
} // else {throw std::exception("wrong parameter type");}
}
};
int main() {
Derived object;
ParameterDerived param("foo");
object.f(&param);
}

C++ member access from a derived class of a templated type

Long story short, what I want here is to declare a templated type in a base class and be able to access that type A<T> such that the base class B contains it and the derived class C is able to access it as C::A<T>. I did try declaring an int inside of class B and that can be accessed from the derived C class as C::int, here's the error!
||In constructor ‘D::D()’:|
|74|error: no match for ‘operator=’ (operand types are ‘A<C*>’ and ‘A<B*>’)|
|4|note: candidate: A<C*>& A<C*>::operator=(const A<C*>&)|
|4|note: no known conversion for argument 1 from ‘A<B*>’ to ‘const A<C*>&’|
And this is the code that does compile ( comment A<B*> i; and uncomment A<C*> i; to get the error).
#include <iostream>
//class with a template parameter
template <class a>
class A
{
private:
int somevalue;
public:
A(){}
~A(){}
void print()
{
std::cout<<somevalue<<std::endl;
}
};
//1. could forward declare
class C;
class B
{
protected:
A<B*> i;
//2. and then use
//A<C*> i;
public:
B(){}
~B(){}
A<B*> get()
{
return i;
}
/*
//3. use this return instead
A<C*> get()
{
return i;
}
*/
};
//specialization of B that uses B's methods variables
class C : public B
{
protected:
public:
C(){}
virtual ~C(){}
void method()
{
B::i.print();
}
};
//class D that inherits the specialization of C
class D : public C
{
private:
A<B*> i;//works
//4. but I want the inherited type to work like
//A<C*> i;// so that the type C* is interpreted as B*
public:
D()
{
this->i = C::i;
}
~D(){}
};
///////////////////////////////////////////////////////////////////////
int main()
{
D* d = new D();
delete d;
return 0;
}
But okay what if we tried this std::list<template parameter> LIST and then plug that in? That's the problem A<T> is std::list.
As far as I understand your issue now you seem to have a std::list<Base *> (renamed B to Base for clarity) and want to fill an std::list<Concrete*> (renamed C to Concrete, it's derived from Base) with it.
For that you need to iterate over the Base* pointers, checking for each whether it can be downcast to a Concrete* and if so adding it to the std::list<Concrete*>. You need to think about what to do if the downcast fails, too.
For all of this to work your Base needs to be a polymorphic base class, that is it must contain a virtual member function (don't forget to make the destructor virtual). Also note that this sounds like a catastrophe waiting to happen in terms of managing ownership of those pointers.
template<typename Base, typename Concrete>
std::list<Concrete*> downcast_list (std::list<Base*> const & bases) {
std::list<Concrete*> result;
for (auto const base_ptr : bases) {
Concrete * concrete_ptr = dynamic_cast<Concrete*>(base_ptr);
if (concrete_ptr != nullptr) {
result.push_back(concrete_ptr);
} else {
// Error or ignore?
}
}
return result;
}
Note: a more idiomatic version of this would use iterators.
I found the pattern to my problem, it's actually really simple and it serves as the base for encapsulating a class type a (which is a template parameter to be passed around, try looking at my question as a reference to class a). The pattern is shown below, it's generally what I wanted. I found it on this webpage Using Inheritance Between Templates chapter 7.5 from the book entitled OBJECT-ORIENTED
SOFTWARE DESIGN
and CONSTRUCTION
with C++ by Dennis Kafura. I'll copy it below the edited code for the sake of future reference in case anyone else needs it.
template <class a>
class B
{
private:
public:
B();
~B();
};
template <class a>
class C : public B<a>
{
public:
C();
~C();
};
This is the code it was adapted from.
template <class QueueItem> class Queue
{
private:
QueueItem buffer[100];
int head, tail, count;
public:
Queue();
void Insert(QueueItem item);
QueueItem Remove();
~Queue();
};
template <class QueueItem> class InspectableQueue : public Queue<QueueItem>
{
public:
InspectableQueue();
QueueItem Inspect(); // return without removing the first element
~InspectableQueue();
};
Try changing this:
#include <iostream>
//class with a template parameter
template <class a>
class A {
private:
int somevalue;
public:
A(){}
~A(){}
void print() {
std::cout<<somevalue<<std::endl;
}
};
//1. could forward declare
class C;
class B {
protected:
A<B*> i;
//2. and then use
//A<C*> i;
public:
B(){}
~B(){}
A<B*> get() {
return i;
}
/*/3. use this return instead
A<C*> get() {
return i;
} */
};
//specialization of B that uses B's methods variables
class C : public B {
protected:
public:
C(){}
virtual ~C(){}
void method() {
B::i.print();
}
};
//class D that inherits the specialization of C
class D : public C {
private:
A<B*> i;//works
//4. but I want the inherited type to work like
//A<C*> i;// so that the type C* is interpreted as B*
public:
D() {
this->i = C::i;
}
~D(){}
};
int main() {
D* d = new D();
delete d;
return 0;
}
To Something Like This:
#include <iostream>
//class with a template parameter
template <typename T>
class Foo {
private:
T value_;
public:
Foo(){} // Default
Foo( T value ) : value_(value) {}
~Foo(){}
void print() {
std::cout<< value_ << std::endl;
}
};
class Derived;
class Base {
protected:
Foo<Base*> foo_;
Base(){} // Default;
virtual ~Base(){}
// Overload This Function
template<typename T = Base>
/*virtual*/ Foo<T*> get();
/*virtual*/ Foo<Base*> get() { return this->foo_; }
/*virtual*/ Foo<Derived*> get();
};
class Derived : Base {
public:
Derived() {}
virtual ~Derived() {}
void func() {
Base::foo_.print();
}
void Foo<Derived*> get() override { return this->foo_; }
};
And this is as about as far as I could get trying to answering your question...
There are objects that you are not using in your code
There are methods that aren't being called.
It is kind of hard to understand the direction/indirection
of what you mean to do with the inheritance tree.
You are inheriting from a base class without a virtual destructor
And probably a few other things that I can not think of off the top of my head right now.
I'd be more than willing to try and help you out; but this is as far as I can go with what you currently are showing.
EDIT -- I made changes to the base & derived classes and removed the virtual keyword to the overloaded function template declarations - definitions belonging to those classes.

Const and non-const version and inheritance

In my problem, I will have a few classes that will share getters and setters (in my case, the operator()). Suppose I have the following
class Base
{
public:
int& operator()() { return value; }
int operator()() const { return value; }
protected:
int value;
};
class Derived : public Base
{
public:
int operator()() const { return value; }
};
I expected being able to do something like this :
Derived d;
d() = 1;
but the compiler complains saying that the expression is not assignable. However, doing this
Derived d;
d.Base::operator()() = 1;
works correctly. Why is that ? Shouldn't the compiler be able to look up for the member function in the base class ? Is there a solution to avoid rewriting the non-const method is the derived class ?
Shouldn't the compiler be able to look up for the member function in the base class?
Yes, it is possible, but you have to be explicit. For that you can use a using declaration, which introduces the operator to the derived class:
class Derived : public Base
{
public:
using Base::operator();
int operator()() const { return value; }
};

base class pointer, invoke method based on derived type

I understand that the following code doesn't work -- can't convert base to foo.
Is there something I can do, or some pattern to employ which would get me close the behavior I'm trying to achieve in the code below? IOW, if I have a base class pointer to a derived type, how can I invoke a specific method that matches the derived type (not the base type)?
What patterns might I use? I looked into Curiously Recursive (or recurring) Template Pattern, however this imposed other limitations itself.
class base {};
class foo : public base {};
void method(const foo& f){}
int main(){
base* b = new foo();
method(*b);
}
The easiest way is probably to just make method() a virtual member function on foo:
class base {
public:
virtual void method() const = 0;
};
class foo : public base {
public:
void method() const override { }
};
int main(){
foo f;
base* b = &f;
b->method();
}
But if for some reason that is not possible (perhaps you don't have access to method() or perhaps you want to keep the logic in method() separate from foo) you could use a simplified version of the Visitor Pattern.
The visitor pattern relies on all the classes in your hierarchy having a virtual function to dispatch based on class type.
In your case you don't need double-dispatch so you don't actually need the visitor object and can just call your method function directly from a virtual dispatch function:
class base {
public:
virtual void dispatch() const = 0;
};
class foo : public base {
public:
void dispatch() const override;
};
void method(const foo& f){}
void foo::dispatch() const {
method(*this);
}
int main(){
foo f;
base* b = &f;
b->dispatch();
}
You have to remember that in most contexts the compiler doesn't know that your base pointer is actually of type foo.
Use virtual functions to solve these kinds of problems:
class base {
public:
virtual void func() const { /* A */ }
};
class foo : public base {
public:
void func() const override { /* B */ }
};
void method(const base& f) {
f.func();
}
int main(){
base* b = new foo();
method(*b);
}
Now, depending on the actual type of f, either A or B code will be executed in method.

When protected protects too much

This is about "protected", which is explained as: "When a class inherits another one, the members of the derived class can access the protected members inherited from the base class." However, look at this code:
class Base {
public:
Base( int m ) : member(m){}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base x ){
return value - x.member;
}
private:
int value;
};
Derived accesses "x.member", which is protected in its Base class, right? But the compiler flags an error, "Base::member is protected". And, after mulling this over for a minute, I had to agree with the compiler.
And here comes the question: How do I make this work, with a minimum loss of information hiding?
Clearly, making "member" public compiles, but it's against the original intent.
Using the "friend" mechanism in Base to let subclasses access "member" (and everything else that's private and protected) is even worse (apart from the dumb binding of a superclass to its own subclasses - a maintenance nightmare).
In the simple example, a public int getMember(){ return member; } would be acceptable. But if member's type is a X*, the best you can do is a public const X* getMember(){...}.
Did I miss something?
You can keep the protected attributes, add the getter functions as you mentioned. As for a protected pointer attribute, the getter would make sure that int (or a const ref for a large object) is returned and you can do the difference in a function template that takes Derived and Base arguments then (getters give you the values for the calculation).
Protecting data attributes allows direct access to the protected attribute within the derived class. What you tried is to access a private attribute of another object. This part of your code:
int diff( Base x ){
return value - x.member;
}
would be equivalent to writing this in main:
Base x;
cout << x.member << endl;
Here is an example of how to solve the problem using the option 3 you suggested yourself, with a derived class PointerDerived that is using pointers for the storage:
#include <iostream>
class Base {
public:
Base( int m ) : member(m){}
int getMember() const
{
return member;
}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return value;
}
private:
int value;
};
class PointerDerived : public Base { // one of several subclasses
public:
PointerDerived( int m ) : Base(m), value(new int (10)) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return *value;
}
~PointerDerived()
{
delete value;
value = nullptr;
}
private:
int* value;
};
template<typename Derived, typename Base>
int diff(const Derived& d, const Base& b)
{
return d.getValue() - b.getMember();
}
using namespace std;
int main(int argc, const char *argv[])
{
PointerDerived p(23);
Base q(1);
cout << diff(p, q) << endl;
return 0;
}
Compile the program with -std=c++11 because of the nullptr, or change it to NULL.
You make the diff a function template, so that you don't have to overload it for each and every derived class, and you let the derived class handle the storage and access to it as does for example PointerDerived.
You can use a static protected accessor:
class Base {
public:
Base( int m ) : member(m){}
private:
int member;
protected:
static int GetMember(const Base &b)
{ return b.member; }
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base &x ){ //beware of your slicing!
return value - GetMember(x);
}
private:
int value;
};
Now let me add my idea of why C++ access control works this way...
Access control in C++ is not about information hiding. It is about encapsulation. That is, plainly speaking, you filter out the access to any member that can break the class if used incorrectly.
In an ideal class
public members cannot be used to break the object.
private members know what they are doing.
As you see, in my scheme there is little place for protected members:
protected members are used to implement the inheritance interface, if any.
And even less place for protected member variables.
So make your variable private, and write a protected accessor. The accessor must be static to be able to be used from the derived object.