When and why would you declare an abstract class as a friend class?
I am trying to read the source code of levelDb
It has an interface (abstract class) DB which does not have access to DB_Impl:
class DB {
public:
static Status Open(const Options& options,
const std::string& name,
DB** dbptr);
DB() { }
virtual ~DB();
virtual Status Put(const WriteOptions& options,
const Slice& key,
const Slice& value) = 0;
virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;
virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;
virtual Status Get(const ReadOptions& options,
const Slice& key, std::string* value) = 0;
virtual Iterator* NewIterator(const ReadOptions& options) = 0;
virtual const Snapshot* GetSnapshot() = 0;
virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;
virtual void GetApproximateSizes(const Range* range, int n,
uint64_t* sizes) = 0;
virtual void CompactRange(const Slice* begin, const Slice* end) = 0;
private:
// No copying allowed
DB(const DB&);
void operator=(const DB&);
};
and the implementation DB_Impl.
In db_impl.h:
class DBImpl : public DB {
public:
... // implementation of the DB interface
private:
friend class DB;
... // internal methods and variables
}
Why is the abstract class DB declared as a friend class of DBImpl?
An abstract class can have (and often has) non-abstract parts, for example normal member functions.
In your example, DB may have some normal member function f() { /* ... */ }. Furthermore, the class design may be such that DB is aware of certain derived classes. This is often, but not always, a sign of broken class design. So f may actually take a DBImpl argument and need to access some of its private members. In such a scenario, friend achieves the desired results.
Here is a complete example:
class DBImpl;
class DB {
public:
virtual ~DB() {}
void f(DBImpl& db_impl); // DB is aware of a derived class
private:
virtual void virtual_function() = 0; // just to make the class abstract
};
class DBImpl : public DB {
private:
void virtual_function() override {} // just to make the class concrete
void g() {} // DBImpl wants only DB to be able to call this
friend class DB;
};
void DB::f(DBImpl& db_impl) {
db_impl.g(); // DB can call DBImpl's private member function
}
May be the static function DB::Open in DB class is using DBImpl private/protected member variables/function.
Also if you havent shown the complete DB class declaration here and it has extra code please check if there is any non pure virtual function of DB class, it may have instance of DBImpl and access to its private member variables. This function can be inherited in derived classes and if called using derived class instance it will work fine.
Hope this helps.
Related
I have a pure virtual class Interface:
class Interface {
public:
virtual ~Interface() noexcept;
virtual void open()=0;
virtual void close()=0;
protected:
explicit Interface(const string params);
string params_;
}
I then have an abstract class where I implement my business logic:
template<typename T>
class AbstractInterface : public Interface {
public:
void open() override;
void close() override;
void read_is_complete(const vector<byte_array>);
protected:
explicit AbstractInterface(const string params);
virtual ~AbstractInterface() noexcept;
}
Then there is the implementation for the interface that uses CRTP for polymorphism:
class SPInterface : public AbstractInterface<SPInterface> {
public:
explicit SPInterface(const string params);
virtual ~SPInterface() noexcept;
void open();
void close();
void read_is_complete(const vector<byte_array> data);
}
I have a unit test where I create an instance of SPInterface:
unique_ptr<Interface> intf;
intf.reset(new SPInterface("aaa"));
Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:
template<typename T>
void AbstractInterface<T>::close() {
static_cast<T *>(this)->close();
params_ = "";
}
Which is confusing as I already created an instance of the class. lldb seems to confirm:
AbstractInterface<SPInterface>::close(this=<unavailable>)
Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:
template<typename T>
void AbstractInterface<T>::close() {
static_cast<T *>(this)->close();
params_ = "";
}
It seems that you are trying to invoke a method of a derived class from within the destructor of a base class.
This is not safe at all and a segfault is the way the executable has to tell you that it doesn't approve that. :-)
Even though CRTP allows you to invoke a member function that belongs to the derived class on a (let me say) living object, it doesn't change the way an object is destructed.
Do not forget that bases and members are destroyed in the reverse order of the completion of their constructor.
i want to understand the behavior of pure virtual functions in derived class when passing to it an argument of same type as (abstract) base class.
to clarify the question, i took the following code from GeeksForGeeks and modified it:
namespace example {
enum Type {ENGINEER, MANAGER};
class Employee
{
private:
const Type worker;
public:
Employee(const Type& worker) : worker(worker) {}
virtual ~Employee {}
virtual void raiseSalary(const Employee&) = 0;
{ /* common raise salary code */ }
virtual void promote(const Employee&) = 0;
{ /* common promote code */ }
};
class Manager: public Employee {
private:
int degree;
public:
//<constructor>\\
virtual void raiseSalary(const Employee&)
{ /* Manager specific raise salary code, may contain
increment of manager specific incentives*/ }
virtual void promote(const Employee&)
{ /* Manager specific promote */ }
};
}
Now, how can we get access to the field degree in derived class Manager inorder to update his degree? since the passed argument to raiseSalary(Employee& employee) could be Manager or Engineer
I think there are two ways to handle that problem. Let's start with some really bad solution: using casting. In that case dynamic_cast. You can try to down cast a type. If dynamic_cast isn't able to do that it is going to return a null pointer or throw an exception (depends on wheather you cast a pointer or a value/reference type). But that approach is going to force you to adapt your casts as more Manager, Engineer types are going to come. You might also need to use friend to allow specific classes to access internals of others. friend is not going to be inherited in the hierarchy, so you are going to end up with many friends => broken, broken, broken :(
An alternative would be to use the Visitor Pattern: http://en.wikipedia.org/wiki/Visitor_pattern
Using the visitor pattern you can also make a base no-op visitor and finer grained Visitors to handle specific stuff. Just a small example (with specific visitors without derivation):
namespace example {
class SalaryRaisingVisitor;
class EmployeePromotingVisitor;
class Employee
{
public:
Employee() {}
//don't forget to implement the copy constructor: read more about rule of 3!!!
virtual ~Employee {}
virtual void accept(SalaryRaisingVisitor const&) = 0;
virtual void accept(EmployeePromotingVisitor const&) = 0;
};
class Manager: public Employee {
private:
int degree;
public:
//<constructorS>
virtual void accept(SalaryRaisingVisitor const& v)
{
v.visit(*this, degree);
}
virtual void accept(EmployeePromotingVisitor const& v)
{
v.visit(*this, degree);
}
};
class Engineer: public Employee {
public:
//<constructorS>
virtual void accept(SalaryRaisingVisitor const& v)
{
v.visit(*this);
}
virtual void accept(EmployeePromotingVisitor const& v)
{
v.visit(*this);
}
};
class SalaryRaisingVisitor
{
void visit(Manager& m, int& degree) //might be const if no internal state changes
{
//...
}
void visit(Engineer& e) //might be const if no internal state changes
{
//...
}
};
}
At the end as you deal with C++, try to avoid virtual functions :) and move everything to static polymorphism :)
You are getting the concept of virtual functions with classes wrong. The class "knows" what it is (via vtable), so you can just write it as class function, not as static global function. Each function inside the class knows all class variables, so you don't have to pass an object of the class.
namespace example {
enum Type {ENGINEER, MANAGER};
class Employee
{
private:
const Type worker;
public:
Employee(const Type& worker) : worker(worker) {}
virtual ~Employee {}
virtual void raiseSalary() = 0;
{ /* common raise salary code */ }
virtual void promote() = 0;
{ /* common promote code */ }
};
class Manager: public Employee {
private:
int degree;
public:
//<constructor>\\
virtual void raiseSalary()
{
//the Employed standard code
Employee::raiseSalary(); //This won't compile since you set the virtual function = 0
//Manager specific raise salary code
degree = 0; //this lazy bastards should do real work like coding stuff
}
virtual void promote()
{
Employee::promote(); //employee common code. This won't compile since you set the virtual function = 0
/* Manager specific promote */
degree = degree * 2;
}
};
Employee array[10];
array[0] = Manager(); //create a manager object on the stack
array[1] = Manager(); //create a manager object on the stack
array[0].raiseSalary(); //Only Mananer0 gets raiseSalary
/*the manager object in array[0] uses its virtual function
to the manager raiseSalary function. The Manager RaiseSalary function
in this case calls the base class raiseSalary function explicitly
via Employee::raiseSalary(); */
You should rather structure your code like this:
class Employee
{
virtual void raiseSalary() = 0;
virtual void promote() = 0;
};
class Manager: public Employee
{
virtual void raiseSalary()
{ /* Manager specific raise salary code, may contain... */ }
virtual void promote()
{ /* Manager specific promote */ }
};
int main()
{
Manager bob;
bob.promote(); // <--- Proper method in the Manager class will be called.
// Current instance will always have the right class.
}
In other words you should seek opportunity to pass the specific derived class as the this parameter. Unfortunately this will not work in complex cases when multiple params are needed. But well, this was the idea of the language designers. The perfect language is not developed yet.
I think that you can't and it's the wanted behaviour.
The only way to do this is to cast you argument (which is quite complicated in C++ since you have four different kind of casting). Other solution is to give to any employee a grade attribute.
Alexis.
I will start with my design:
class IOutputBlock{
public:
virtual void write(char *) = 0;
virtual bool hasMemory() = 0;
virtual void openToWrite() = 0;
};
class IInputBlock{
public:
virtual bool hasNext() = 0;
virtual IField *next() = 0;
virtual void openToRead() = 0;
};
class MultiplicationNode : public OperationNode
{
public:
MultiplicationNode(Node *l, Node *r);
~MultiplicationNode(void);
virtual bool hasNext();
IInputBlock * evaluate();
};
class IOBlock: public IInputBlock, public IOutputBlock{
virtual void write(char *);
virtual bool hasMemory();
virtual void openToWrite();
virtual bool hasNext();
virtual IField *next();
virtual void openToRead();
};
Inside the evaluate method i need to create an IOuputBlock to write data in the block.
I want the MultiplicationNode consumer just see method for iterate over the block (IInputBlock interface).
But in the return of evaluate method, I have to perform a typecast.
Is this implementation correct? Or is it an example of bad design?
Can u suggest another design? Or maybe design pattern to help.
IInputBlock * MultiplicationNode::evaluate()
{
IOutputBlock *outputBlock = new IOBlock();
//need to write to outputblock
return (IInputBlock *)outputBlock;
}
I could also do this below, but I don't think it is right, because i was violation "program to an interface", and exposing unnecessary methods inside evaluate method from IInputBlock interface.
IInputBlock * MultiplicationNode::evaluate()
{
IOBlock *outputBlock = new IOBlock();
//need to write to outputblock
return outputBlock;
}
One option is to separate read and write classes (even if underlying data is shared):
class WriteOnlyBlock: public IOutputBlock{
// return new instance of something like ReadOnlyBlock
// potentially tied to same internal data
public: IInputBlock AsRead()...
}
This way you make conversion explicit and prevent callers from attempting to cast IInputBlock to IOutputBlock and minimize number of extra methods exposed by each class.
I have a design question. I want custom datatypes implementing an interface. For example, using templates is simply (maybe next design isn't correct -because I can do a generic class instead of the next- but clarifies my goal):
template <typename T>
class IDatatype
{
public:
virtual T getData() const = 0;
virtual void setData(T pData) = 0;
};
class MyChar: public IDatatype<char>
{
public:
void setData(char pData){...}
char getData() const{...}
private:
char _data;
};
class MyInt: public IDatatype<int>
{
public:
void setData(int pData){...}
int getData() const{...}
private:
int _data;
};
IDatatype<int> *data = new MyInt(); // parametrized interface, bad idea :(
data->getData(); // it works ok
From previous classes, it is easy to get the attribute corresponding to each _data class member. My question:
Is there any way (change design, etc.) to implement generic setter and getter in IDatatype
and for any type and thus manipulate the _data attribute of each class
without using templates in the interface?
For example:
class IDatatype
{
public:
// pure virtual getters and setters for specialized _data fields. Here is my design question.
};
class MyChar: public IDatatype
{
public:
void setData(char pData){...};
char getData(){...};
private:
char _data;
};
class MyInt: public IDatatype
{
public:
void setData(int pData){...};
int getData(){...};
private:
int _data;
};
IDatatype *intData = new MyInt(); // no parametrized interface!
intData->getData(); // how can I create this method from IDatatype?
IDatatype *charData = new MyChar();
charData->getData(); // the same here
NOTE: I have no good english, apologize for any errors :)
You could probably achieve this in 3 ways, none as elegant and error free as using a template
Define your data as a union of int/float/char in the base class and act on this union from the set/get methods of the base class. The entire VB (old VB 6) class system works on such a data type called VARIANT.
Return void * from base class and cast and use as appropriate - yuck & good luck!!.
Return the base interface reference itself from the getData which though appearing to be meaningful, has no meaning at all.
4.
I have an inheritance hierarchy and I want to make each class in this hierarchy have a set of attributes which are particular for that class and which do not change during the run of the program. For example:
class Base
{
public:
const std::string getName() const;
bool getAttribute1() const;
int getAttribute2() const;
};
Now I want these functions to return the same result all the time. Furthermore, when another class inherits Base this class should have its own set of attributes and any instance of this derived class should have the same attributes. Also the name should be unique for each class.
I want to know a way to make this as transparent and elegant as possible. Sofar I have considered 2 ideas that I can use:
Make some lock system.
That is provide setters for these attributes, but make them throw a runtime exception when they are called more than once.
Make the getters pure virtual.
In this case, the result of the functions would not be stored inside the object itself. This would make it vaguely clear that the result depends on the dynamic type.
Both ideas sound incredibly lousy, so I need your help.
I am new to C++, but I know there are a lot of idioms and patterns to solve general problems like this one. Do you know any?
I have an inheritance hierarchy and I want to make each class in this hierarchy have a set of attributes which are particular for that class and which do not change during the run of the program
Well, then just provide the corresponding values as arguments to a class constructor, and do not expose any setter method on the public interface. This will make sure the values remain constant throughout the life-time of the object.
To protect against possible errors that would alter the value of those data members from member functions of your class (which of course can access the private data), make those data members const. Notice, that this will force you to initialize those members in the constructor's initializer list.
class Base
{
public:
// Forwarding constructor (requires C++11)
Base() : Base("base", true, 42) { }
const std::string getName() const { return _s; }
bool getAttribute1() const { return _a1; }
int getAttribute2() const { return _a2; }
protected:
// Constructor that can be called by derived classes
Base(std::string s, bool a1, int a2)
: _s(s), _a1(a1), _a2(a2) { }
private:
const std::string _s;
const bool _a1;
const bool _a2;
};
Derived classes would then just construct the base subobject with the appropriate arguments:
class Derived : public Base
{
public:
// Provide the values for the constant data members to the base constructor
Derived() : Base("derived", false, 1729) { }
};
This way you would not incur in the overhead of a virtual function call, and you won't have to rewrite similar virtual functions for each of these members in derived classes.
Make them virtual and hard-code the result which the functions should return:
class Base
{
public:
virtual const std::string getName() const { return "BaseName"; }
virtual bool getAttribute1() const { return whatEverAttributeValueYouWant; }
virtual int getAttribute2() const { return attributeValueHere; }
};
class Derived : public Base {
public:
virtual const std::string getName() const { return "DerivedName"; }
virtual bool getAttribute1() const { return whatEverOtherAttributeValueYouWant; }
virtual int getAttribute2() const { return otherAttributeValueHere; }
};
If you want to describe classes rather than objects, use (kind-of) traits:
template<class T> struct AttributeValues;
template<> struct AttributeValues<Base> {
static const std::string name () { return "BaseName"; }
};
template<> struct AttributeValues<Derived> {
static const std::string name () { return "DerivedName"; }
};
//...
auto nameBase = AttributeValues<Base>::name ();
auto nameDerived = AttributeValues<Derived>::name ();