Redundant private member data replication in implementation hierarchy - c++

My question concerns the combination of public and private inheritance as a tool to separate interface and implementation in a C++ class. In this pattern, the interface base class declares the common functions (class Base0). The common implementation is carried out in a class derived virtually from the interface base (class Impl0 : virtual public Base0). This class contains any common data members. The extension classes are written in two steps. First the extended interface is defined by virtual inheritance from the interface base (class Base1 : virtual public Base0). Second, the extended implementation is carried out by deriving publicly from Base1 (for interface) and privately from Impl0 (for implementation): class Impl1 : public virtual Base1, private Impl0. My questions are the following:
(1) if the functions in the extension class define functions that require common data in Impl0, do I have to replicate that data in `Impl1'?
(2) Is there any way to avoid this replication?
As a minimal example, consider a class hierarchy for implementing the four basic arithmetic functions: add(), substr(), mult() and div(). The basic version, MathOps, contains the add() and subtr() functions. The extended version, MathOps_Extn, contains mult() and div(). The above technique gives the following class hierarchy.
#include<iostream>
using std::cout;
using std::endl;
class MathOps {
public:
virtual int add(int x) = 0;
virtual int subtr(int x) = 0;
};
class MathOps_Impl : public virtual MathOps {
private:
int m_y;
public:
MathOps_Impl(int y) : m_y(y) {
cout << "MathOps_Impl initialized with value: " << m_y << endl;
}
virtual int add(int x) { return x + m_y;}
virtual int subtr (int x) { return m_y - x;}
};
class MathOps_Extn : public virtual MathOps {
// Extends MathOps by adding mult() and div()
public:
virtual int mult(int x) = 0;
virtual int div(int x) = 0;
};
class MathOps_Extn_Impl : public virtual MathOps_Extn, private MathOps_Impl {
private:
int m_y; // Have to replicate member data m_y here.
public:
MathOps_Extn_Impl(int y) : MathOps_Impl(y), m_y(y) {
cout << "MathOps_Extn_Impl initialized with value: " << m_y << endl;
}
virtual int mult(int x) {
return x * m_y;
}
virtual int div(int x) {
int quotient = x == 0? 0 : m_y/x;
return quotient;
}
};
int main() {
MathOps_Extn* B = new MathOps_Extn_Impl(10);
cout << "add 20: " << B->add(20) << endl;
cout << "subtr 20: " << B->subtr(20) << endl;
cout << "mult 2: " << B->mult(2) << endl;
cout << "div 5: " << B->div(5) << endl;
Note the replication of m_y in MathOps_Extn_Impl. Is there any way to avoid this replication?

Note the replication of m_y in MathOps_Extn_Impl. Is there any way to
avoid this replication?
Yes. Give MathOps_Impl::m_y protected access instead of private.
You're explicitly asking why derived classes can't access private data. That's by design.

You can give access to the common data, without breaking encapsulation, via protected member functions in the common implementation class.
Gratuitous example follows :)
#include <cstdio>
class Math
{
public:
virtual ~Math() {}
virtual int add(int b) const = 0;
};
class MoreMath : public virtual Math
{
public:
virtual ~MoreMath() {}
virtual int subtract(int b) const = 0;
};
class MathImpl : public virtual Math
{
private:
int m_a;
public:
MathImpl(int a) : m_a(a) {}
virtual ~MathImpl() {}
int add(int b) const { return m_a + b; }
protected:
int value() const { return m_a; }
};
class MoreMathImpl : public virtual MoreMath, private MathImpl
{
public:
MoreMathImpl(int a) : MathImpl(a) {}
int subtract(int b) const { return value() - b; }
};
int main()
{
MoreMath* one = new MoreMathImpl(1);
printf("1 + 2 = %d\n", one->add(2));
printf("1 - 2 = %d\n", one->subtract(2));
delete one;
return 0;
}

Related

Get properties of derived class from base class argument

I not sure how to ask this but basically i pass a base class as an parameter and if the argument is a derived class from the base class i want to be able to access properties only in the derived class
class A{
public:
bool isB = false;
int x = 69;
}
class B : public A{
public:
bool isB = true;
int y = 420;
}
void Print(A c){
if (c.isB)
cout << c.y << endl; //this will error as the class A has no y even though i will pass class B as an argument
else
cout << c.x << endl;
}
A a;
B b;
Print(a);
Print(b);
My recommendation is that you use polymorphism by creating a virtual "print" function that your global Print function calls:
class A
{
int x = 69;
public:
virtual ~A() = default; // Needed for polymorphic classes
virtual void print(std::ostream& out) const
{
out << x;
}
};
class B : public A
{
int y = 420;
public:
void print(std::ostream& out) const override
{
out << y;
}
};
void Print(A const& o)
{
o.print(std::cout);
std::cout << std::endl;
}
int main()
{
A a;
B b;
Print(a);
Print(b);
}
You need to define a virtual function "bool amIaB()" in both base and derived class that returns "isB".

Accessing Inherited Functions

In multiple inheritance,where all the base class contains same function name with different functionality, we can access the protected function from particular base class using "::" scope resolution operator.
However, I tried something else. I created the objects of the base class in inside the child class. And tried calling the function using through object of that particular class.
But I was getting the following compiler error:
"‘void A::func(int&)’ is protected within this context."
Please let me know where did i go wrong.
#include <iostream>
using namespace std;
class A
{
protected:
void func(int & a)
{
a = a * 2;
}
};
class B
{
protected:
void func(int & a)
{
a = a * 3;
}
};
class C
{
protected:
void func(int & a)
{
a = a * 5;
}
};
class D : public A,public B,public C {
public:
int a;
A a_val;
B b_val;
C c_val;
void update_val(int new_val)
{
a = new_val;
a_val.func(a);
b_val.func(a);
c_val.func(a);
}
void check(int);
};
void D::check(int new_val)
{
update_val(new_val);
cout << "Value = " << a << endl;
};
int main()
{
D d;
int new_val;
cin >> new_val;
d.check(new_val);
}
If you want to keep your code with the base classes as having independent functionality and still remaining protected the easiest way to resolve your issue is by slightly changing the name of your protected functions and adding a public function that calls the protected members: See these class declarations for example:
class A {
public:
void func( int& a ) {
func_impl( a );
}
protected:
void func_impl( int& a ) {
a = a * 2;
}
};
class B {
public:
void func( int& b ) {
func_impl( b );
}
protected:
void func_impl( int& b ) {
b = b * 3;
}
};
class C {
public:
void func( int& c ) {
func_impl( c );
}
protected:
void func_impl( int& c ) {
c = c * 5;
}
};
class D : public A, public B, public C {
public:
int a;
A a_val;
B b_val;
C c_val;
void update_val( int val ) {
a = val;
a_val.func( a );
b_val.func( a );
c_val.func( a );
}
void check( int );
};
void D::check( int val ) {
update_val( val );
std::cout << "Value = " << a << std::endl;
}
This provides a nice public interface to call the protected member functions. This also resolves the issue of accessing the protected members. When I run your program and input a value of 5 it returns a result of 150 and works as expected.
This snippet should show you how inheritance works and when you can and can not access protected members:
class DerivedA : public Base {
public:
Base b;
void call_message() {
b.message(); // Protected Member of Base class can not be accessed
}
};
class DerivedB : public Base {
public:
void call_message() {
message(); // This works without problem!
}
};
Just as I did above one way to resolve this is by adding a public interface caller to the protected implementation.
class Base {
public:
void message() {
message_impl();
}
protected:
void message_impl() {
std::cout << "This is a protected member of Base\n";
}
};
Now you can do this:
class DerivedA {
public:
Base b;
void call_message() {
b.message(); // Accessible through public interface.
}
};
When you are in your derived class, it has access to its own ancestor methods. But it doesn't have access to your variables member protected and private methods and variables.
Redesign your code, you are trying things and contorting the other classes design for bad reasons. Francis' code is a good solution, but D doesn't need to inherit from anything.
If you don't want to create another function, you can do something like this:
#include <iostream>
using namespace std;
class A
{
protected:
void func(int & a)
{
a = a * 2;
}
};
class B
{
protected:
void func(int & a)
{
a = a * 3;
}
};
class C
{
protected:
void func(int & a)
{
a = a * 5;
}
};
class D : public A,public B,public C {
public:
int a;
void update_val(int new_val)
{
a = new_val;
this->A::func(a);
this->B::func(a);
this->C::func(a);
}
void check(int);
};
void D::check(int new_val)
{
update_val(new_val);
cout << "Value = " << a << endl;
};
int main()
{
D d;
int new_val;
cin >> new_val;
d.check(new_val);
}
This works because, this refers to the current instance of class D, and it already inherits class A, class B, class C. So you can directly access the protected functions of the respective classes.
Remember: It will not work if you have not inherited the classes.

Multiple "level" derived abstract classes with

I have a problem in C++ where I have
One abstract base class with common members and pure virtual functions. This is A in the code below.
Multiple derived classes with different members and functions. This is B and C in the code below.
Multiple derived classes that implements the virtual functions and has no new members. This is do_stuff_1 and do_stuff_2 in the code below.
My solution so far is to mix templates and abstract classes. The goal is to hold a pointer to the abstract classes B orC and call do_stuff. My questions are
Is my solution a good one?
If not, are there better solutions?
If so, are there some pitfalls I should be aware of?
Here is my solution so far
#include <iostream>
#include <memory>
/* base virtual class */
class A {
public:
int a;
A(int a) : a(a) {}
virtual void do_stuff() = 0;
};
/* concrete implementations of do_stuf */
template<class T>
class do_stuff_1 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_1 " << this->a << std::endl;
}
};
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(int a, int b): A(a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A(a), c(c) {}
};
int main() {
std::unique_ptr<B> x;
x.reset(new do_stuff_1<B>(1, 1));
x->do_stuff();
std::cout << x->b << std::endl;
x.reset(new do_stuff_2<B>(1, 2));
x->do_stuff();
std::cout << x->b << std::endl;
std::unique_ptr<C> z;
z.reset(new do_stuff_1<C>(1, "Yo"));
z->do_stuff();
std::cout << z->c << std::endl;
z.reset(new do_stuff_2<C>(1, "Hello"));
z->do_stuff();
std::cout << z->c << std::endl;
return 0;
}
The result is
do_stuff_1 1
1
do_stuff_2 2
2
do_stuff_1 1
Yo
do_stuff_2 2
Hello
Your solution seems fine. It's a compile time approach and you create 4 different objects.
The main drawbacks are:
you won't know if the do_stuff() code is correct unless you instantiate the template.
you could instantiate do_stuff_1 or do_stuff_2 with classes which are not of base class A. You should at least use override in the template to make sure it overrides a virtual function.
Here a small improvement to address these issues:
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff() override {
static_assert (std::is_base_of<A, T>::value, "T should be derived from A");
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
By the way, using make_unique would be nice.
To me looks like some kind of policy, this may look like:
#include <iostream>
#include <memory>
#include <type_traits>
struct AwayToDoTheStuff {
virtual void operator()(int a) = 0;
virtual ~AwayToDoTheStuff() {}
};
/* concrete implementations of do_stuf */
class HowToDoStuff1 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_1 " << a << std::endl;
}
};
class HowToDoStuff2 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_2 " << a + 1 << std::endl;
}
};
/* base virtual class */
template <class HowToDoStuff>
class A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A<HowToDoStuff>(a), c(c) {}
};
int main() {
B<HowToDoStuff1>(1, 1).do_stuff();
B<HowToDoStuff2>(1, 2).do_stuff();
C<HowToDoStuff1>(1, "Yo").do_stuff();
C<HowToDoStuff2>(1, "Hello").do_stuff();
return 0;
}
but I must say this is quite hard to tell if a solution match well with an example that much generic. I hope it will help you in some ways...
EDIT:
You seem to need to have a common base class so that you can pass your objects B and C to a common function of the kind void f(A &a);
Then my example can be adapted that way:
/* base virtual class */
class A {
public:
void do_stuff() = 0;
};
template <class HowToDoStuff>
class Policy_A : public A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() override {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public Policy_A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): Policy_A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public Policy_A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): Policy_A<HowToDoStuff>(a), c(c) {}
};
So that the do_stuff can be called on opaque A objects.
You may also pass the HowToDoStuff object at creation:
/* base virtual class */
class A {
std::unique_ptr<AwayToDoTheStuff> _stuffer;
public:
int a;
A(std::unique_ptr<AwayToDoTheStuff> stuffer, int a) : _stuffer(std::move(stuffer)), a(a) {}
void do_stuff() {
(*_stuffer)(a);
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, int b): A(std::move(stuffer), a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, std::string c): A(std::move(stuffer), a), c(c) {}
};
int main() {
auto stuffer1forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
B(stuffer1forB, 1, 1).do_stuff();
B(stuffer2forB, 1, 2).do_stuff();
auto stuffer1forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
C(stuffer1forC, 1, "Yo").do_stuff();
C(stuffer2forC, 1, "Hello").do_stuff();
return 0;
}

Avoid code duplication in a pair of almost identical base > derived classes

I have a pair of base/derived classes which are almost identical, but not quite.
I could simply copy all the code of Base1 > Derived1 to create Base2 > Derived2, but that would be ugly, and would require making almost any modification twice.
Question: How can I share as much code as possible between the two pairs, to avoid code duplication?
I tried to create a small toy example that has most features of the actual problem. I want to avoid having duplicate code for the identical part of the interface of D1 and D2. If you want to see more of the actual problem, scroll to the end of the question.
#include <iostream>
using namespace std;
//////////// 1st PAIR ////////////
class B1 {
protected:
string name;
public:
B1() : name("B1") { } // constructors are different between B1 and B2
void speak() { cout << name << endl; } // identical between B1 and B2
};
template<typename T>
class D1 : public B1 {
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
// differences between D1 and D2 follow:
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 {
protected:
string name;
public:
B2() : name("B2") { }
void speak() { cout << name << endl; }
};
template<typename T>
class D2 : public B2 {
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
The interface of B1 and B2 can be shared by making them inherit from a class BInterface.
It was suggested to me to use multiple inheritance to be able to do the same with D1 and D2, through an additional base class DInterface. Furthermore, it was suggested I try to use the curiously recurring template pattern to allow this additional base class to access the members of D1 and D2. My attempt at doing this follows. I find it a bit complicated, and I would like to know if this is a reasonable approach, and whether there is a better way to do the same.
#include <iostream>
using namespace std;
//////////// COMMON INTERFACES ////////////
class BInterface {
protected:
string name;
BInterface(const string &n) : name(n) { }
public:
void speak() { cout << name << endl; }
};
template<typename D>
class DInterface {
private:
D &derived() { return *static_cast<D *>(this); }
protected:
DInterface() {}
public:
int getX() { return derived().x; }
int nameLength() { return derived().name.size(); }
};
//////////// 1st PAIR ////////////
class B1 : public BInterface {
public:
B1() : BInterface("B1") { } // constructors are different between B1 and B2
};
template<typename T>
class D1 : public B1, public DInterface< D1<T> > {
friend class DInterface< D1<T> >;
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 : public BInterface {
public:
B2() : BInterface("B2") { }
};
template<typename T>
class D2 : public B2, public DInterface< D2<T> > {
friend class DInterface< D2<T> >;
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
Since several people have commented that this is too broad, and that the context from my actual problem is lost, below I will describe the actual problem:
Mathematica has a C extension API. Certain data types, such as dense or sparse arrays or images can be manipulated in C. I am working on a much easier to use C++ interface. The system also includes in interface generator: a lot of glue code is automatically generated based on a symbolic representation of a C++ class interface in Mathematica. Here's an older version of the system.
I am now working on handling images. Mathematica has Image and Image3D, distinct expressions for 2D and 3D images. Image can also have different pixel types, such as byte, 16-bit, floating point, etc.
The C API uses a single representation for all of these, including 2D and 3D images, called MImage (a pointer type, multiple MImages may point to the same image in memory).
It is convenient for have separate classes for 2D and 3D images in C++, and also to template these on the pixel type. These correspond to the D1 and D2 classes above. However, in some cases, it is useful to operate with "generic" images that may have any pixel type (pixels can't be accessed in this case, but we can do other things with the images too). This is why I also have the base classes B1 and B2.
Here's the implementation of 2D image references so far (this is not done and it will change). I still need to add 3D images, which will share a lot of code.
This solution factors out the concepts of having a name and having a value through a base class that has a name.
If the individual components of the derived classes do not depend on each other then this kind of inheritance composition is relatively easy to maintain.
If the concerns of the base classes are interdependent then you'll have to use CRTP and marshal calls via the derived class.
#include <iostream>
using namespace std;
// factor out common parts
struct NamedThing
{
NamedThing(std::string &&name) : name(std::move(name)) {}
NamedThing(std::string const& name) : name(name) {}
void speak() { cout << name << endl; }
std::size_t nameLength() const { return name.size(); }
private:
std::string name;
};
template<class T, class Base>
struct NamedValue : public Base
{
T x; // identical between D1 and D2
public:
NamedValue(T const& v)
: Base()
, x(this->nameLength())
{}
T getX() { return x; } // identical between D1 and D2
};
//////////// 1st PAIR ////////////
class B1 : public NamedThing
{
public:
B1() : NamedThing("B1") { } // constructors are different between B1 and B2
};
template<typename T>
class D1 : public NamedValue<T, B1> {
using inherited = NamedValue<T, B1>;
public:
D1(const T &a)
: inherited(a)
{
}
// differences between D1 and D2 follow:
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 : public NamedThing
{
public:
B2() : NamedThing("B2") { }
};
template<typename T>
class D2 : public NamedValue<T, B2> {
using inherited = NamedValue<T, B2>;
public:
D2(const T &a)
: inherited(a)
{
}
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
Where you want to inherit for code reuse you can use private inheritance. With private inheritance the derived classes are blocked from being cast to their base classes.
#include <string>
#include <iostream>
class super
{
std::string name_;
public:
super( std::string n ): name_(n) {}
virtual ~super(){}
std::string name() const { return this->name_; }
void name( std::string n ) { this->name_ = n; }
};
class base1: private super
{
int vertices_;
public:
base1( std::string n, int v ): super( n ), vertices_( v ) {}
virtual ~base1() {}
using super::name; // make both name methods accessible
int vertices() const { return this->vertices_; }
void vertices( int v ) { this->vertices_ = v; }
};
class base2: private super
{
std::string surname_;
public:
base2( std::string n, std::string s ): super( n ), surname_( s ) {}
virtual ~base2() {}
// to make only one name method accessible
std::string name() const { return this->super::name(); }
std::string surname() const { return this->surname_; }
};
// class derived1: public base1 { ... };
// class derived2: public base2 { ... };
int main()
{
base1 v1( "triangle", 3 );
base2 v2( "john", "doe" );
std::cout << "base1: " << v1.name() << " " << v1.vertices() << "\n";
std::cout << "base2: " << v2.name() << " " << v2.surname() << "\n";
v1.name( "square" );
v1.vertices( 4 );
std::cout << "base1: " << v1.name() << " " << v1.vertices() << "\n";
//v2.name( "jane" ); // illegal code
//super *p1 = &v1; // illegal code
//super *p2 = &v2; // illegal code
//derived1 d1(...);
//derived2 d2(...);
//base1 *p1 = &d1; // allowed
//base2 *p2 = &d2; // allowed
//derived1 *p1 = dynamic_cast< derived1* >((super*)&d2); // Not allowed
return 0;
}
With private inheritance you cannot directly access any base class methods outside the derived class. You have two options to allow this: (1) In base1 we use a public using statement to make the two name methods accessible. (2) In base2 we only want one of the name functions so we write a stub method that calls the super class method (NOTE: as this is inline it should result in the same assembly code as the using method).

Calling overridden function and using overloaded variable from base class

I have two base classes and derivered versions that overload / override certain parts like this:
class base
{
public:
int X = 1;
};
class deriv : public base
{
public:
int X = 2;
};
class A
{
public:
base K;
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
};
class B : public A
{
public:
deriv K;
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
};
the application looks like this
int main()
{
A instanceA;
B instanceB;
instanceA.doSmth();
instanceB.doSmth();
getchar();
return 0;
}
And the output therefore is X=1 for both instances A and B. I was wondering why that is.
A uses base (X=1) and B uses deriv (X=2). deriv overloads X and B overloads K. Is this because the function smthElse() is only defined in A, thus A can't know about the existance of the overloaded variable K?
If so, is there a way for the function smthElse() to use the overloaded variable K?
I found the using keyword but also adding a using A::smthElse; in B won't change the behaviour of X not being printed as 2. The only way I can achieve this is by copying the function smthElse() from A and insert it into B.
Is there a different way to achieve what I'm looking for? Since it seems like an overkill to copy'n'paste the same function into B just to use an overridden variable.
Thanks in advance!
instanceB has two variables named K, A::K and B::K. However, the base class, A, only knows about one K, A::K.
That explains the output.
If so, is there a way for the function smthElse() to use the overloaded variable K?
Yes, you can do that by adding a virtual function in A that returns a reference to base and adding a virtual function in base that returns a reference to i.
class base
{
public:
int& getX( return X;}
private:
int X = 1;
};
class deriv : public base
{
public:
int& getX( return X;}
private:
int X = 2;
};
class A
{
public:
base& getK() { return K; }
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << getK().getX() << std::endl;
// ^^^^^^^^^^^^^ use the virtual functions
}
public:
base K;
};
class B : public A
{
public:
deriv& getK(){ return K; }
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
public:
base K;
};
PS I hope this is just curiosity and you don't write production code with such style. You will end up confusing yourself and anybody who tries to understand your code.
When you write
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
smthElse is virtual
K is not (a member variable could not be virtual: it has no meaning for an attribute).
In other terms, it means that B::smthElse will ovevrride A::smthElse but B::K and A::K are two distinct, unrelated and independent variables.
When smthElse is called in the context of a B, K still means A::K.
As a solution, you might create a virtual accessor to Ks:
class base { ...};
class deriv{ ...};
class A
{
base K;
public:
virtual const base& theK() { return K; }
virtual void smthElse() { std::cout << theK().X << "\n"; }
};
class B : public A
{
deriv K;
public:
virtual const base& theK() { return K; }
};
When B{}.smthElse() is called, it will call B::theK() which will return B::K (a deriv instance).