Nested overloaded operator->() in C++ - c++

Can the operator->() expand more than once when the classes having this operator overloaded nest each other?
In the further sample the expression c->foo() expands to c.operator->()->foo() and I would expect the second iteration of expansion to occur, but it does not happen. Is there any way to overload the operator to use it when nested with a neat syntax?
class A
{
public:
void foo() {}
}
class B
{
private:
A* _a;
public:
A* operator->() const
{
return _a;
}
};
class C
{
private:
B* _b;
public:
B* operator->() const
{
return _b;
}
};
C c;
c->foo(); // Desired syntax, but error: 'foo' is not a member of 'B'
c.operator->()->operator->()->foo(); // Ok, but makes no sense
Please consider this question theoretical!

Chaining only occurs when the result is another class type. You'd need to make the C version be something like:
B& operator->() const
{
return *_b;
}
Obviously beware of the possibility of _b being a null pointer in the real code.

Related

C++ rules for covariant virtual function

I was reading Covariant virtual function. It says that
Suppose that B::f overrides the virtual function A::f. The return types of A::f and B::f may differ if all the following conditions are met:
1) The const or volatile qualification of the pointer or reference
returned by B::f has the same or less const or volatile qualification
of the pointer or reference returned by A::f.
2) A::f returns an lvalue reference if and only if B::f returns an
lvalue reference.
3) The function B::f returns a pointer or a reference to a class of
type T, and A::f returns a pointer or a reference to an unambiguous
direct or indirect base class of T.
4) The return type of B::f must be complete at the point of declaration of B::f, or it can be of type B
Will someone explain the above 2 rules by giving suitable example? What exactly these 2 rules mean?Is the second rule is applicable from C++11?
Is the following example satisfies 1st rule I've said here?
#include <iostream>
class Base {
public:
virtual const Base& fun() const
{
std::cout<<"fun() in Base\n";
return *this;
}
virtual ~Base()
{ }
private:
int a=3;
};
class Derived : public Base
{
const Derived& fun() const
{
std::cout<<"fun() in Derived\n";
return *this;
}
};
int main(){
Base* p=new Derived();
p->fun();
delete p;
return 0;
}
Please correct me If I am wrong somewhere.I am confused in first 2 rules.
Thanks
Your help will be highly appreciated.
The first rule means that you can't make an overridden function return a B which has const or volatile if the A version does not:
struct A
{
virtual A* foo() { return new A{}; }
};
struct B : A
{
B* foo() override {return new B{}; } //valid
const B* foo() override {return new B{}; } //invalid
volatile B* foo() override {return new B{}; } //invalid
};
This makes sense if the think about the call site:
A* my_b = new B{};
A* new_b = my_b->foo(); //discards the const qualifier if B::foo() returns const B*
The second rule means that you can't have disparate reference or pointer types as covariant return types. Using the same example as above:
struct A
{
virtual A* foo() { return new A{}; }
};
struct B : A
{
B* foo() override {return new B{}; } //valid
B& foo() override {return new B{}; } //invalid
B&& foo() override {return new B{}; } //invalid
};
Again, think about the call site:
A* my_b = new B{};
A* new_b = my_b->foo(); //if B::foo() returns a reference, this line is syntactically ill-formed
Your example satisfies both rules because both return types have the same cv-qualification and are both lvalue references.

Calling constant function from another class object

Here is the code that i have
class A
{
public:
void Func1() const;
};
class B
{
public:
A* a;
void Func2() const
{
// do something with 'a'
}
};
void A::Func1() const
{
B b;
b.a = this;
b.Func2();
}
Now obviously this is giving me an error in the line, because I'm trying to convert from const to non-const.
b.a = this;
Is there any way to call Func2 without having to cast away the constness of this. Since Func2 is a const function anyways, it will not change this.
You have to declare the A* as const:
class A
{
public:
void Func1() const;
};
class B
{
public:
const A* a;
void Func2() const
{
// do something with 'a'
}
};
void A::Func1() const
{
B b;
b.a = this;
b.Func2();
}
Since in A::Func1, the this pointer is const.
If class B is always going to work with *a as a const object then as others have said all it takes is to simply change the declaration to
public: const A* a
At this point I should mention that the constness of B::Func2 is a red herring because it has absolutely no relation to the constness of B::a. That B::Func2 is const means that it's not allowed to change the value of a; however, it is allowed to dereference a and mutate the resulting object.
Now, if class B has both const and non-const operations with respect to *a then your class design needs to change. It would be much better if you switched class B to use a const A* a as above, and added another class D : public B that encapsulates all the mutating operations. In addition, a should be hidden behind a property setter; this allows you to do things like
class B {
const A* a;
public:
void setA(const A* a) { this->a = a; }
void Func2() const {}
};
class D : public B {
A* a;
public:
using B::setA;
void setA(A* a) {
this->a = a;
static_cast<B*>(this)->setA(const_cast<const A*>(a));
}
void Func3() { /* do something to D::a */ }
};
With this scheme both B and D keep independent, suitably typed pointers to the object to be accessed. If setA is called on a B, or on a D with a const A* parameter then only B::a is set. If setA is called on a D with an A*, then both B::a and D::a are properly set. This has become possible because by abstracting the member behind a setter you can then overload the setter on the constness of its parameter.
Func2 may not change this, but b.a is not const and you're free to change it afterwards. There's no right way to do this, although workarounds exist, such as mutable or const_cast.
It's the sign of a faulty design.
Yes, make the A * constant:
class B {
public:
const A *a
...
};

C++ pointers and classes

Trying to solve this question for the last 45 minutes, but couldn't figure out the what I'm suppose to do. Here's the question.
class C; //forward declaration
class Cpointer {
public:
};
class C { //do not modify
int i;
public:
C(int _i=0) : i(_i) {}
Cpointer operator& () { return Cpointer(this); }
void Do() { std::cout << "i=" << i << std::endl; }
};
int main() {
Cpointer p (new C(100));
p->Do();
}
Complete class Cpointer so that the code compiles. Make sure there are no memory leaks.
As I understand CPointer class takes a C class as a parameter for the constructor.
When I try the below code I'm getting a compiler error telling that
"use of undefined type C" inside the CPointer's Do function.
class Cpointer
{
C* mCptr;
public:
Cpointer(C* cptr) : mCptr(cptr){}
void Do()
{
//mCptr->Do();
}
};
I feel slightly uneasy posting solution but since you say it's not a homework... Here it is:
class Cpointer {
C* ptr;
public:
Cpointer(C* c) : ptr(c) { }
~Cpointer() { delete ptr; }
C* operator->() { return ptr; }
};
There are three points here:
Constructor to get the C* pointer and store it in the improvided pointer-like class.
Destructor to remove the object heap-allocated C when p gets out of scope of main function.
Overloaded -> operator so that p->Do(); will correctly invoke the C::Do method.
Basically, what you were asked to implement is a partial functionality of the standard auto_ptr class.
Given the way Cpointer is used in main(), it has to be implemented like this:
class Cpointer
{
private:
C* c:
public:
Cpointer(C* _c) : c(_c) {}
~Cpointer() { delete c; }
C* operator ->() { return c; }
};
The problem is that Cpointer is also used by C's overriden '&' operator, and this kind of implementation will not work for that usage. Memory corruption will occur, especially if the C instance is declared on the stack (which is when an overriden '&' operator is usually needed). To really make this work correctly, C would have to be modified, either to stop using Cpointer, or to contain a reference count that Cpointer manages. Either way violates the "do not modify" restriction on C.
so that it compiles, and doesn't leak? ok.
class Cpointer
{
public:
Cpointer(C* c)
{ delete c; }
void Do()
{ }
Cpointer* operator ->()
{ return this; }
};
class C; //forward declaration
class Cpointer {
public:
C* mptr;
Cpointer(C *cptr){
mptr = cptr;
}
~Cpointer(){
delete mptr;
}
C* operator->() const {
return mptr;
}
};

How to return a const ref to a struct object such that all its nested structures also are read only?

How do I prevent all the member variables in a nested struct to be non modifiable?
typedef struct A
{
int a;
int b;
}A1;
typedef struct B
{
A1* objA;
}B1;
class C
{
public:
const B& GetB() const { return objB; }
PopulateB();
private:
B objB;
};
int main()
{
C objC;
objC.PopulateB();
const B& objB2 = objC.GetB();
objB2.objA->a = 3; // compiler allows this
}
I just want a struct that is completely read only and I expected this to work. (In this case objB2)
The pointer is const. The data it points to is not. Thats just how pointers work The best solution is to not expose raw pointers. A non-const accessor function would not be allowed on a const reference, so you can avoid the tricky indirection.
As an aside, you don't have to typedef structs like that. It's a C-ism.
The pointer type in your struct B refers to a non-const value, and this is the definition that counts. If you wanted to control access, you should hide data members and provide accessors and mutators:
struct B
{
private:
A1* objA;
public:
A1 & a1() {return *objA;}
A1 const & a1() const {return *objA;}
};
You can try:
typedef struct B
{
const A1& objA;
}B1;

Typecast operator overloading problem

For example i have two classes A and B, such that for two objects a and b, i want to be able to do :
A a;
B b;
a = b;
b = a;
for this i have overloaded the = operator, and the typecast operators as:
class A{
-snip-
operator B()const { return B(pVarA); }
};
class B{
-snip-
operator A()const { return A(pVarB); }
};
but when i try to compile this code, gcc throws the error :
error: expected type-specifier before 'B'
for the line: operator B()const { return B(pVarA);}
my guess is, this is due to a chicken and egg problem as class B is defined after class A.
Is there a way to circumvent this while still using the overloaded typecast operators. And if not, then what might be the best way to achieve my goals.
Any help will be appreciated. Thanks in advance.
Try forward declaring then supplying the actual function definitions later on:
class B;
class A{
-snip-
operator B()const;
};
class B{
-snip-
operator A()const;
};
inline A::operator B() const
{
return B(pVarA);
}
inline B::operator A() const
{
return A(pVarB);
}
This should work:
class B;
class A{
operator B()const;
};
class B{
operator A()const { return A(pVarB); }
};
A::operator B() const { return B(pVarA); }