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; }
};
Related
I have several c++ classes that have similar behaviours. Moreover most of the class methods can be constructed from few fundamental ones. So I want to define a base class with the derived methods, inherit from the base class and define the remaining methods in the derived classes.
This is my attempt using the CRTP
template <class derived_class> class base_class {
public:
virtual derived_class& operator++ () = 0;
virtual derived_class& fun1() = 0;
derived_class operator++ (int) {
derived_class toreturn(static_cast<derived_class&>(*this));
++*this;
return toreturn;}
derived_class& fun2() {
this->fun1();
return static_cast<derived_class&>(*this);
};
};
class deriv1 : public base_class<deriv1> {
public:
int n;
deriv1():n(0){};
deriv1(deriv1& other):n(other.n){};
deriv1& operator++ () override { ++n; return *this;}
deriv1& fun1() override { n *= n; return *this;}
};
I don't understand why fun2() works but not the postscript increment.
If I call the postscript increment on a derived object I get the error message "Cannot increment value of type 'deriv1'".
The solution is to add a using statement:
class deriv1 : public base_class<deriv1> {
public:
....
using base_class::operator++;
};
The problem is that function resolution is failing. Lets think of a simpler solution to illustrate the problem:
struct Base
{
void f() {}
void f(int) {}
};
struct Derived: public Base
{
void f() {}
};
int main()
{
Derived a;
a.f(1); // This fails as there is no f() that takes an integer
// in Derived. And since the compiler found an f() in
// Derived it stopped looking further up the chain
// for additional matches.
}
This problem is solved in the same way.
struct Derived: public Base
{
using Base::f;
void f() {}
};
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(¶m);
}
I know it's OK to call base class function in a derived class constructor, because base class is constructed before derived class.But I'm not sure if this is a good practice.Example code is:
class Base {
public:
int Get() const { return i_; }
void Set(const int i) { i_ = i; }
private:
int i_{0};
};
class Derived : public Base {
// initialize `derived_i_` with a call to base class function, Is this a good
// practice in production code?
Derived() : derived_i_{Get()} {
// do some other things
}
private:
int derived_i_{0};
};
To be more pedantic, you could write your constructor as the following:
Derived() : Base(), derived_i_{Get()} {
// do some other things
}
The compiler should fully construct the base class before doing any initialization of the derived class.
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;
};
I tried using CRTP with this (simplified) example:
Base class:
template <class Derived>
class Base
{
public:
int method(int in, int& out2)
{
return derived().method(in, out2);
}
int method(int in)
{
int dummy;
return this->predict(in, dummy);
}
protected:
Base() {}
private:
Derived& derived()
{
return *static_cast<Derived*>(this);
}
};
Derived class:
class Derived : public Base<Derived>
{
public:
int method(int in, int& out2)
{
// Logic here
}
};
The problem is, when I try to use method(int in) with an instance of the Derived class, like:
Derived d;
int res = d.method(5);
The compiler (icc in this case, but have also tried with msvc) gives me the following error:
error #165: too few arguments in function call
It seems that the compiler is not realizing that there exists an overload which only takes one parameter, from the Base<Derived> class (from which Derived inherits publicly, so I think it should be accesible).
I'm not sure what I'm missing here, any hints will be deeply appreciated.
The presence of Derived::method means that the compiler will not consider overloads of Base::method when attempting to bind the call. To fix this, add using Base::method; to the derived class:
class Derived : public Base<Derived>
{
public:
using Base::method;
int method(int in, int& out2)
{
// Logic here
}
};
When a non-virtual function is defined with the same name as a Base::method, it overshadows the Base::method in the Derived class, which is also known as Name Hiding.
To prevent this, you have to explicitly mention the name of the method with the class using the using operator, i.e. your Derived class code should be modified to:
class Derived : public Base<Derived>
{
public:
using Base::method; //makes the 'method' declaration of Base class
//visible here as well.
int method(int in, int& out2)
{
// Logic here
}
};