I saw the example below in an SO question about preventing class inheritance, and I didn't understand why it should work : If I have a class "CTest" that inherits publicly CBase, the compilation fails because in constructor 'CTest::CTest()' 'CSealed::CSealed()' is protected. If I get rid off the virtual keyword, the compilation succeeds, why ?
class CSealed
{
protected:
CSealed()
{
}
};
class CBase : virtual CSealed
{
public:
CBase() {
}
};
class CTest : public CBase
{
public:
CTest() { std::cout << "TEST !!!!\n " << std::endl; }
};
The code you've posted,
class CSealed
{
protected:
CSealed()
{}
};
class CBase : virtual CSealed
{
public:
CBase()
{}
};
will not permit CBase to be derived from. That's because the virtual base class must be initialized by the (each) constructor of the most derived class. And since the virtual base is a private base class, it's not accessible to a class derived from CBase.
E.g., this class derivation,
class CTest
: public CBase
{};
should not compile it CTest is ever instantiated.
However, as a matter of fact, while it fails to compile with Visual C++ 2015, it does compile with MinGW g++ 6.3.0, so in practice it's not entirely reliable.
Instead of this old C++03 technique you can just use C++11 final:
class CBase final
{
public:
CBase()
{}
};
Related
I feel like this is a pretty basic C++ question. I am trying to make a class which contains a member variable which is a shared_ptr to any class which is derived from a specific interface, but does not care which particular derived class it is. I am implementing it as follows:
class Base
{
public:
Base();
virtual void do_stuff() = 0;
};
class Derived : Base {
Derived() {}
void do_stuff() { };
};
class Foo
{
public:
Foo() {
mPtr = std::make_shared<Derived>();
}
protected:
std::shared_ptr<Base> mPtr;
};
Compiling gives the following error at the top:
error: no match for ‘operator=’ (operand types are ‘std::shared_ptr<Base>’ and ‘std::shared_ptr<Derived>’)
mPtr = std::make_shared<Derived>();
What's the proper way to do this?
Edit: Changing inheritence from Base to public Base made it work. However, trying to instantiate the class makes the linker break.
Foo foo;
Compiling gives
libfoo.so: undefined reference to `Base::Base()'
collect2: error: ld returned 1 exit status
What's this about?
Fixed the access specifiers and more:
#include <memory>
class Base {
public:
Base() = default; // must have implementation
// virtual dtor - not strictly needed for shared_ptr:
virtual ~Base() = default;
virtual void do_stuff() = 0;
};
class Derived : public Base { // public inheritance
public: // public access
// Derived() {} // not needed
void do_stuff() override {}; // mark override
};
class Foo {
public:
Foo() :
mPtr{std::make_shared<Derived>()} // use the member init-list
{}
private: // prefer private member variables
std::shared_ptr<Base> mPtr;
};
Derived should use public inheritance, rather than private inheritance, and Derived() should be public.
class Derived : public Base
{
public:
Derived() {}
void do_stuff() override{ };
};
Following explanation and examples from here I have exemplary constructed the following inheritance model creating a diamond
class Base {
public:
int data_;
Base(int d) : data_(d) {}
Base() = deleted;
};
class A : public virtual Base {
public:
A() : Base(42) {};
};
class B : public virtual Base {
public:
B() : Base(24) {};
}
class AB : public A, public B {
public:
AB() : Base(-1) {};
}
so far so good; note, that AB() needs to call to the Base(int)-ctor now. This is kind of understandable, because having the alternative initializer branches of going through AB>>A>>Base or AB>>B>>Base would not result in a well defined behavior at that.
Lets branch out from class A into a side-branch before we even have closed the diamond:
class A_Child : public A {
public:
A_Child() : A() {}; // not permitted by compiler
}
This will not compile, as the compiler will explicitly ask for to specify the ctor Base(int) in the inializer list of A_Child.
I don't quite understand this behavior; as we are no longer virtually inheriting at this point and the path of initalization of A_Child>>A>>Base is not ambiguous.
It seems now for every furthermore derived class of A_Child I have to again specify the Base(int) initializer explicitly. This is kind of breaking the encapsulation as every code that derives from this class needs to know how the class at the very base acts and is implemented.
Is there any way to stop or to break the virtual inheritance once I branch into a side-line?
I have a basic base class and a couple of sub-classes which inherit from it.
Class Base{
public:
Base(){};
virtual ~Base();
virtual void foomethod()=0; //Marked as pure virtual
};
Class A : public Base{
A(){}; //Ctor
~A(){}; //Dtor
void foomethod(){ /* DO SOMETHING */ }
}
Class B : public Base{
B(){}; //Ctor
~B(){}; //Dtor
void foomethod(){ /* DO SOMETHING */ }
}
Use of the above is throwing an error in the following usage:
Base a = A();
Base b = B();
The compiler is complaining about the function foomethod() being pure virtual.
However, when the following is used, there is no problem.
A a = A();
B b = B();
I would have thought that the first instance should be accepted due to C++'s principles of polymorphism. I want to enforce a specific method implementation of the method in sub-classes. If it is marked as virtual only, there is not guarantee that it will be explicitly overrided.
There are several issues with your code, I'll try to get most of them:
You can't have a pure function without marking it as virtual
You can't create objects of an abstract Base class (there's no code for the methods)
When you write
Base b = A();
you're creating two objects and then assigning the A object to the Base b object. This cannot happen since Base is abstract but in cases where this can happen you could experience the slicing problem.
You marked the destructor as virtual in the derived classes but not in the Base (and no definition either), always mark it as virtual when using virtual polymorphism otherwise derived destructors will not be called
This is a more correct way of doing it:
#include <iostream>
using namespace std;
class Base{
public:
Base(){};
virtual ~Base() {};
virtual void foomethod()=0; //Marked as pure virtual
};
class A : public Base{
public:
A(){}; //Ctor
virtual ~A(){}; //Dtor
void foomethod(){ cout << "Hello from A"; }
};
class B : public Base{
public:
B(){}; //Ctor
virtual ~B(){}; //Dtor
void foomethod(){ /* DO SOMETHING */ }
};
int main() {
// Base obj; // Can't do that
Base *obj = new A();
obj->foomethod(); // A's one
delete obj;
return 0;
}
http://ideone.com/gvcL9S
Oh and there were some syntax errors here and there.. and a visibility problem if you intend to use those functions from the outside.. but I believe the excerpt was just a pseudocode one.
Consider this example of code:
class Base
{
public:
Base() {}
};
class Derived1 : public Base
{
public:
Derived1() : Base() {}
};
class Derived2 : public Base
{
public:
Derived2() : Base() {}
};
Is there any to make that Derived1 has-a Derived2 and Derived2 has-a Derived1?
The best solution would be by using a third class which has those two objects. But in case high performance is needed?
An example might be a two-way client-server application.
EDIT: Consider that that's just a summary example. In the real code each of the three classes could throw an exception; I made sure that the code is exception-safe, though.
You can accomplish a "has-a" relationship with a forward declaration which basically tells "this class exists, it's just not declared yet"
#include <iostream>
using namespace std;
class Base
{
public:
Base() {}
};
// Forward declaration
class Derived1;
class Derived2 : public Base
{
friend class Derived1;
public:
Derived2() : Base() {}
private:
Derived1 *ptr;
};
class Derived1 : public Base
{
public:
Derived1(Derived2& obj) : Base(), ptr(&obj) {
obj.ptr = this;
}
private:
Derived2 *ptr;
};
int main() {
Derived2 obj2;
Derived1 obj1(obj2);
return 0;
}
http://ideone.com/RVU8AR
This way the two classes can communicate with each other. Notice the private pointers and the initialization into the constructor. With the "friend" declaration one class is able to modify the other class's private members.
Each class can hold a pointer:?
class Derived1
Derived2 *p_d2;
class Derived2
Derived1 *p_d1;
Must virtual methods be always implemented in derived class?
Can I write something like this?
<!-- language: lang-cpp -->
class BaseInterface
{
public:
virtual void fun_a() = 0;
virtual void fun_b() = 0;
virtual ~BaseInterface();
};
class Derived : public BaseInterface
{
void fun_a() { ... };
};
class FinalClass : public Derived
{
void fun_b() { ... };
}
int main()
{
FinalClass test_obj;
test_obj.fun_a(); // use Derived implementation or fail ???
test_obj.fun_b(); // use own implementation
BaseInterface* test_interface = new FinalClass();
test_interface->fun_a(); // fail or ok ???
test_interface->fun_b();
}
Is the code above correct?
Does another virtual method outflank exist?
Pure virtual methods always must be reimplemented in derived class?
Actually a derived class which is going to be instantiated.
In your code, you didn't make an object from Derived so it's OK.
Can i write something like this?
Yes.
You had some minor errors that I corrected them:
class BaseInterface
{
public:
virtual void fun_a() = 0;
virtual void fun_b() = 0;
virtual ~BaseInterface() {}; // You forget this
};
class Derived : public BaseInterface
{
public:
void fun_a() {} // This should be public as its base
};
class FinalClass : public Derived
{
public:
void fun_b() {} // This should be public as its base
};
int main()
{
FinalClass test_obj;
test_obj.fun_a();
test_obj.fun_b();
BaseInterface* test_interface = new FinalClass();
test_interface->fun_a();
test_interface->fun_b();
}
It makes Derived also an abstract class which you cannot instantiate, seeing you don't implement all the virtual functions from it's base, it becomes an abstract class you cannot directly instantiate.
See here: liveworkspace.org/code/6huYU$10
For the rest, your code should work.
Code is correct.
There is no special concept for interface in C++. All are classes. Some of the class methods can be pure virtual. It only means that compiler cannot create an instance of such class.