Lets say I have something like the following:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
}
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
something_complicated& A::get_complicated() { return b_->x; }
Unfortunately, in this case, a.cpp will fall to compile because "get_complicated()" is not a method of A.
So, we can try this:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
something_complicated& A::get_complicated();
}
But then a.hpp fails to compile because something_complicated isn't defined.
We could forward declare something_complicated if it is a class, but it's probably a typedef, so that is out.
The only way I can think of doing this without making b_ public nor including something_complicated.hpp in a.hpp is the following:
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
#define get_complicated ((b_->x))
Surely I don't have to define a macro to get around this issue? Any alternatives?
The easiest solution is probably to wrap a reference to the complicated type in a class, forward declare that in a.hpp, and define it in something_complicated.hpp.
a.hpp:
class B;
class complicated_ref;
class A
{
public:
complicated_ref get_complicated();
private:
std::unique_ptr<B> b_;
};
something_complicated.hpp:
// ... complicated definitions ...
typedef whatever something_complicated;
struct complicated_ref
{
complicated_ref(something_complicated & thing) : ref(thing) {}
something_complicated & ref;
};
Now a.cpp and anything that needs to use the complicated type must include it's header, but anything that just wants to use class A does not need to.
This is assuming that there's a good reason for some clients of A to access the complicated thing, but for B to be inaccessible to everyone. It would be simpler still to allow access to B when required, and get to the complicated thing through that.
I am afraid there is a misunderstand on what belong to the class, and what does not.
Not all methods that act on the internals of the class should be class methods, after all, we have friend functions already. I know that many people declare the helper methods as private functions, however doing so introduces needless dependencies (compile-time) and a visibility issue with friends.
When dealing with PIMPL, I tend not to use private functions. Instead, the choice is:
Making Impl (B in your case) a true class, with its own validation logic and true API
Using static free functions (or functions declared in an anonymous namespace)
Both are good, and use whichever seems most appropriate. Namely:
methods: when dealing with validation issues
free functions: for computing that can be expressed in terms of the aforementionned methods
It is deliberate on my part to search to have as few methods as possible, because those are the only ones that can screw up my class invariants, and the less they are the more confident I can be that the invariants will be maintained.
In your case, it's up to you to decide which approach suits you best.
In Action:
a.cpp
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
static something_complicated& get_complicated(B& b) { return b_.x; }
// or anonymous namespace instead
namespace {
something_complicated& get_complicated(B& b) { return b_.x; }
}
Not so different from what you had, eh ?
Note: I prefer static functions to anonymous namespaces because it's more obvious when reading. Namespaces introduce scopes, and scope are not glanced easily when sifting through a file. Your mileage may vary, both offer identical functionality (for functions).
Just avoid referring to something_complicated in a.hpp.
One solution is to replace the member function get_complicated with a free function, or a static method of another class.
.h:
class A_impl_base {
A_impl_base() {}
friend class A_impl; // all instances of A_impl_base are A_impl
}; // this stub class is the only wart the user sees
class A
{
private:
std::unique_ptr< A_impl_base > b_; // this is not a wart, it's a pimpl
friend class A_impl;
}
.cpp:
class A_impl : A_impl_base {
static A_impl &get( A &obj ) { return * obj.b_; }
static A_impl const &get( A const &obj ) { return * obj.b_; }
};
What's wrong with:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
public:
B& get_B();
}
If your clients want to get something complicated out of B, then let them #include <something_complicated.hpp>.
We could forward declare something_complicated if it is a class, but it's probably a typedef, so that is out.
This is exactly what you have to do. And I don't see how being a typedef rules out a forward declaration.
If you control something_complicated.hpp you could do what the standard library does: Create a something_complicated_fwd.hpp that has appropriate forward declarations, including the types that may or may not be typedefs.
Related
I have a class A and class B which both have the same methods and variables, but B has one additional variable (which is completely independent from other class members).
So it would be something like:
class A
{
void Foo();
bool m_var;
}
template< class T >
class B< T >
{
// Same stuff
void Foo();
bool m_var;
// Unique stuff
T m_data;
}
Normally, I would use inheritance B : public A, but I want to keep these classes super tight and I don't want to have vtable ptr inside them (as I'm not gonna use polymorphy anyway). What's the best approach to achieve that? I was thinking about templates and their specialization - having class A<T> and A<void>, but I need to remove something, not add. Is there any smart template trick which I could use?
I was also thinking about creating base class (without virtual dtor) with all common functionalities as a private nested class and inherited classes A< T > : public Base and empty B : public Base as public nested classes. It wouldn't allow anyone from outside to use base class ptr, but it doesn't sound like the purest solution... Is there any "valid" solution for my problem?
As long as you don't use the word virtual, you won't get a vtable. But you're right to think that inheritance is an awkward solution to this problem. Languages like Rust, Scala, and Haskell have a unit type () for data we don't care about. C++ approximates this (albeit poorly) with void, but it really only works as a function return type. My recommendation is to create your own well-behaved unit type.
struct Unit {};
Nice, empty type. There's only one meaningfully distinct instance of Unit, namely Unit(). Then A is just B<Unit>. The Unit m_data in B<Unit> contains no actual information and will likely be optimized out by the compiler.
As already answered, vtable pointers are only added to a class when they are needed. As long as there is nothing marked as virtual anywhere in either your base or derived class, the compiler will not generate a vtable for your type.
If you want to reuse A when writing B, why can't you just use plain old composition?
class A {
bool _var;
public:
explicit A(bool v);
void foo();
// accessors, which could be constexpr
bool var() const; // get
void var(bool n_v); // set
};
template<class T>
class B {
T _data;
A _a;
public:
B( /* params */);
void foo() { this->_a.foo(); }
// forward to A
bool var() const { return this->_a.var(); } // get
void var(const bool n_v) { this->_a.var(n_v); } // set
// add more stuff here
};
If you really are into nasty shenanigans, you might consider taking the private inheritance route, which is functionally the same thing (but less clean, IMHO):
template<class T>
class B : private A {
T _data;
public:
B( /* params */);
using A::foo; // reexports A::foo() as B::foo()
// generates
// - bool B::var()
// - void B::var(bool)
using A::var;
// add more stuff here
};
I was shocked today by the fact that this code snippet has an ambiguous name reference:
class A
{
private:
typedef int Type;
};
class B
{
public:
typedef int Type;
};
class D : A, B
{
Type value;//error: reference to 'Type' is ambiguous
};
Hmm! Imagine you are the author of class A and your class has already been used everywhere by different people and different projects. One day you decide to rewrite your A class. Doesn't this mean that you cannot use any new (even private) name in your new class without breaking others' code?
What is the convention here?
Yes you are right. Using the current format/logic/coding style might break others' code if you decide to make changes later.
Try to use PIMPL or fully qualify symbols.
You're example is a good one of why it's not a good idea to not use fully qualify symbols.
It's the same issue with code like:
using namespace std;
The line of code above could break a lot of stuff.
As #Jarod42 mentioned it needs to follow pimpl idiom (pointer to implementation) to separate interface and implementation:
A.h
#include <memory>
class A
{
public:
A();
~A();
private:
class AImpl;
std::unique_ptr<AImpl> pimpl;
};
A.cpp
#include "A.h"
class A::AImpl
{
private:
typedef int Type;
/* .. */
};
A::A(): pimpl(new AImpl)
{
}
A::~A() = default;
main.cpp
#include "A.h"
class B
{
public:
typedef int Type;
};
class D : A, B
{
Type value;
};
I see no issue here, it's not because it's private that the symbol does not exists. If you try to access a private member the compiler tells you that you can't access it, not that does not exists.
Also, I would say it's a bad practise to use multiple inheritence and not fully qualify symbols.
class D : A, B
{
B::Type value;
};
I have a question which is basically the quite opposite of this one.
As we can see in this post, Java does have one more access mode than C++ : package one.
In my code, I would like to make a class that only some other class could instantiate and use, from its own namespace, and not outside. So it looks like a Java "package-privacy access" case, but this option is not available in C++.
My idea to implement it is to make constructor/destructor and most of methods of this class as private or protected, and to give access to other classes from the same namespace with friend keyword.
But, almost everywhere on forums as on my personal talks with other C++ programmers, friend is considered as an evil keyword that destroy every OOP concept and should never be used.
Would it be adequate to use it in this precise case ? Or is there any other solution without friend use ?
When you use friend you won't be able to restrict access to anything private (e.g. member variables).
I may have a better solution.
You define a struct with a private constructor that defines all classes in your "package" as friend.
Then you change the constructor(s) of the classes you want to restrict in access from outside the package to take a reference to that object.
#include <iostream>
#include <vector>
struct code_unlocker
{
friend struct A;
friend struct B;
friend struct C;
private:
code_unlocker() {};
};
struct A
{
A(const code_unlocker&) //Restricted: Only callabble by friends of code_unlocker
{
};
};
struct B
{
B(const code_unlocker&) //Restricted: Only callabble by friends of code_unlocker
{
A a = A(code_unlocker()); //Works
};
};
struct C
{
C()//Accessible from outside
{
B b = B(code_unlocker()); //Works
};
};
using namespace std;
int main(int, char *[])
{
A a = A(code_unlocker()); //Doesn't work
B b = B(code_unlocker()); //Doesn't work
C c = C(); //Works
}
I am working on a project that had been thought out, rather poorly. I have subclasses that access each other's member functions. Here's the situation:
class A {
public:
class B;
class C;
};
class A::B {
public:
void f() {
C:g();
}
}
class A::C {
public:
void g() {
B:f();
}
}
This code, obviously, runs into various errors which is too much list here. My question is, what is the solution to such a situation? Is it inheritance? If so, how? Is there any other way for me to preserve the "interplaying"-nature of classes B and C.
If you mean C:g() --> C::g(), B:f() --> B::f()
You can not call member function without object unless these member functions are static.
Probably a pointer to each other may resolve your issue?
I introduce pointer is because otherwise I need to write something to help with circular include issue. :)
#include <memory>
class A::B {
public:
void f() {
c_->g();
}
std::unique_ptr<C> c_;
}
class A::C {
public:
void g() {
b_->f();
}
std::unique_ptr<B> b_;
}
move method definitions out of class declarations, so both classes will be declared and their methods are visible to each other
I have put several instances of class b in class a but this causes an error as class a does not know what class b is.
Now I know I can solve this problem by writing my file b a c but this messes up the reachability as well as annoys me. I know I can prototype my functions so I do not have this problem but have been able to find no material on how to prototype a class.
does anyone have an example of class prototyping in c++.
as there seems to be some confusion let me show you what i want
class A
{
public:
B foo[5];
};
class B
{
public:
int foo;
char bar;
}
but this does not work as A cannot see B so i need to put something before them both, if it was a function i would put A(); then implement it later. how can i do this with a class.
You can declare all your classes and then define them in any order, like so:
// Declare my classes
class A;
class B;
class C;
// Define my classes (any order will do)
class A { ... };
class B { ... };
class C { ... };
You're looking for declarations.
class A;
class B {
A MakeA();
void ProcessA(A a);
};
class A {
B bs[1000];
};
If you forward declare a class, you can
declare functions taking and returning it or complex types made of it
declare member variables of pointer or reference to it
This basically means that in any case which doesn't end up with instances of A inside B and vice versa, you should be able to declare and define any interface between A and B.
The usual way to resolve circular dependencies is to use a forward declaration:
// Bar.h
class Foo; // declares the class Foo without defining it
class Bar {
Foo & foo; // can only be used for reference or pointer
};
// Foo.h
#include <Bar.h>
class Foo {
Bar bar; // has full declaration, can create instance
}
You can provide a full declaration and definition in another file. Using the forward declaration, you can create pointers and references to the class, but you cannot create instances of it, as this requires the full declaration.
class b;
class a {
public:
b * inst1;
};
class b{
....
};
Is this what you needed ?