0

I have an pre-defined pure abstract class which I don't want to touch. It's declared like:

class A {
public:
  inline virtual ~A();
  A(const A&);
  A operator=(const A&);
  virtual void someMethod();
};

The class has no member variables & none of these functions are having any implementation, so it should be equal to: virtual void someMethod() = 0;. I want to implement this pure abstract class in my own class (because I need to add member variables to implement the function someMethod()) without changing the declaration from class A, but there are two problems:

1.) class A has no default constructor, but only a copy-constructor and assignment operator declared. So I won't be able to create an instance from my subclass, because A::A: no appropriate default constructor available.

2.) Even assuming, class A would have a default constructor declared and defined (If I add A(){} to the class declaration), I would get 2 linker errors for someMethod() and destructor from class A.

My own code looks like:

#include <memory>

class B : public virtual A {
public:
  B() {}
  inline virtual ~B() {}
  B(const B&) {}
  virtual void someMethod() override {}
};

int main(int argc, char*argv[]) {
  auto object = std::make_unique<B>(B());
  return 0;
}

Any advice what I'm doing wrong here?

Constantin
  • 8,721
  • 13
  • 75
  • 126
  • `A` is not an abstract class because of `virtual void someMethod();` – M.M Sep 14 '15 at 04:17
  • `A` is impossible to create any instances of, since it has no constructor other than one that takes another `A`. So you will have to make changes if you want to actually use it. I'd recommend `struct A { virtual void someMethod() = 0; virtual ~A(); }` – M.M Sep 14 '15 at 04:18
  • "so it should be equal to: `virtual void someMethod() = 0;`" But it isn't. If you want to make it abstract, you need the `=0`. – juanchopanza Sep 14 '15 at 04:18
  • 3
    `A` is broken. You have to change it. Its assignment operator is also wrong. – Neil Kirk Sep 14 '15 at 04:19
  • @M.M I'd also recommend a virtual destructor. – Neil Kirk Sep 14 '15 at 04:19
  • if the functions aren't pure virtual (they're not), they must have bodies defined or the linker will complain about it. – Donnie Sep 14 '15 at 04:20
  • There are no inline virtual functions, destructor or otherwise. If you're getting linker errors because of someMethod, it's because of the missing =0, and if that is not what's declared and you expect it otherwise SHOULD work, then you don't have all the source (there would HAVE to be a body for someMethod(); The virtual destructor for A probably has the same issue, you don't have a body for that either. – JVene Sep 14 '15 at 04:20
  • @JVene What do you mean there are no inline virtual functions? – Neil Kirk Sep 14 '15 at 04:21
  • virtual functions can't be expanded inline, they must be function calls. In order to make a function virtual, there has to be an entry in the vtable, which is a pointer to a function - thus, it is not possible for a virtual function to be inline - it has to be called via pointer to function. – JVene Sep 14 '15 at 04:25
  • "inline" means declared with the `inline` keyword, or with the function body defined in the class definition, e.g. `struct A { virtual void foo() {} };` – M.M Sep 14 '15 at 04:26
  • inline means the generated code will be expanded by the compiler without invoking a function call. virtual functions can't do that – JVene Sep 14 '15 at 04:27
  • also, just because a function is written within the class does not mean it will be expanded inline (it may end up doing that if the compiler agrees it qualifies, but it's not automatically so). – JVene Sep 14 '15 at 04:28
  • The compiler can inline virtual functions where the correct function can be determined at compile-time. This most often happens when creating a local variable of a specific type. – Neil Kirk Sep 14 '15 at 04:28
  • It can, that's true, but you can't guarantee that, and you certainly can tell it to do that with the inline keyword before a virtual function declaration. It may not generate an error, but it is likely to be ignored. Further, it will still have an entry in the vtable unless the compiler realizes it is only called in rare situations where it could inline the code. – JVene Sep 14 '15 at 04:29
  • @JVene [This](http://stackoverflow.com/a/733791/4756309) answer talks about an inline virtual destructor. – Weak to Enuma Elish Sep 14 '15 at 04:30
  • Yes, but an inline virtual destructor can only be realized if and only as a result of compiler optimizations. It is not something you can reliably declare, and in all but specialized circumstances is never instantiated as an inline function. It will generated an entry in the vtable and be called as a function, not expanded inline as inline assembler in the output – JVene Sep 14 '15 at 04:31
  • @JVene I don't understand your point. You say it can't happen, then it can. Inlining isn't guaranteed, that's the same regardless of whether it is a virtual function or not. I know at least one real compiler does take into account whether you declare it inline, to determine the likelihood it will be inlined. – Neil Kirk Sep 14 '15 at 04:32
  • Ok, let me put it the way your link put it....it can only happen as a result of the compiler's decision to do so. It is not something you declare and expect that to mean anything. You and I can't really predict, usually, what will occur with a class unless we are the only ones that ever use it. – JVene Sep 14 '15 at 04:33
  • You need to declare it inline if you want to put it in a header file so that it can appear in multiple translation units. – Neil Kirk Sep 14 '15 at 04:34
  • Sorry, still getting used to enter closing an entry....anyway, the point is that declaring a virtual function to be inline suggests you want it to inline that code, and yet, that is actually the result of the compiler optimization, not the fact inline was issued in the declaration, and it happens whether you want it to or not when optimizations are turned on to allow the compiler to do that. The inline keyword itself has no meaning in the context of a virtual function declaration. – JVene Sep 14 '15 at 04:36
  • Unless the virtual function has a body defined in the header, right? – Weak to Enuma Elish Sep 14 '15 at 04:37
  • Everything you are saying equally applies to declaring a non-virtual function inline. The compiler can inline it, if it wants to, but doesn't have to. What's so specially wrong about an inline virtual function? – Neil Kirk Sep 14 '15 at 04:37
  • Neil Kirk....here you have a point, but it should be noted that doing so may still not result in an inline function being expanded as such. Its an odd case where the use of inline in that context is not actually creating an inline function expansion at assembler generation, but merely satisfying the compiler's tendency to complain that a code body appears multiple times. – JVene Sep 14 '15 at 04:37
  • Ah, it's not that it's specially wrong, but that unless there's a reason to use it, it should be learned that it has no purpose. In this case the code doesn't include the body of the function in the class, so inline wasn't even required, and will likely have no effect. If you use the inline keyword, you expect it should do something, even if optional. Here it isn't doing anything to help satisfy a compiler complaint, and the body isn't given (seems to be missing) - which given the inquiry might be an empty function - which, oddly against my own points, would not even generate code. – JVene Sep 14 '15 at 04:40
  • I suggest that since the OP reported linker errors on the destructor, the body must be missing. – JVene Sep 14 '15 at 04:42
  • It does have a purpose - if you want a virtual function to be inlined in certain circumstances and therefore you want to put it in the header. It's not common, but that's a purpose. As the functions are missing bodies it's pointless here, but even non-inline virtual functions need bodies (unless abstract and not a destructor), so I wouldn't consider it the main problem with the code. – Neil Kirk Sep 14 '15 at 04:43

1 Answers1

2

As people in the comments mentioned, A is an impossible class. As it stands, you can only ever create a new A with a preexisting A, so there is no defined way to create an A. I would suggest removing the copy constructor declaration (and definition if you provided one somewhere). You can remove the assignment operator too, unless there actually is a definition for it. Since A has no fields, you might as well make the destructor pure virtual (see this answer about pure virtual destructors).

virtual ~A() = 0;
//outside class definition
inline A::~A() {}

If A has no functionality to include in some_method, just make it pure virtual:

virtual void some_method() = 0;

Also about your class:

class B : public virtual A

I don't think you need A to be a virtual base. Virtual in this context means that if another class inherited both A and B, it would have only one copy of A. These changes should make everything work.

Community
  • 1
  • 1
Weak to Enuma Elish
  • 4,622
  • 3
  • 24
  • 36