How are inline members of classes compiled? - c++

I am new to c++ (and to programming itself) and this is what I heard:
If we compile an ordinary function, The compiler creates a pointer to that function and place the instructions that make up the body of the function elsewhere. This is how an ordinary function gets compiled. But in case of inline functions, the compiler generates code during compilation and replaces it with the inline function call.
My question is when member functions (of a C++ class) are compiled, are they treated as inline functions or are they treated as ordinary functions?

They are just like normal functions, with one exception: if you write the function definition inside the class definition (example below), then the function is automatically given the inline keyword:
[C++11: 9.3/2]: A member function may be defined (8.4) in its class definition, in which case it is an inline member function (7.1.2), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition.
struct T
{
void foo() // the same as `inline void foo()`
{
// ...
}
};
That doesn't automatically mean the class will be inlined, though; the inline keyword is just a hint and is largely ignored nowadays when it comes to deciding whether to actually inline a function, though it does assuredly affect linkage.

You asked:
are they treated as inline functions or are they treated as ordinary functions?
Member functions of classes can be inline or non-inline depending on how they are declared and defined.
Here's the relevant info from the standard:
9.3 Member functions
2 A member function may be defined (8.4) in its class definition, in which case it is an inline member function (7.1.2), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition...
Example:
class A
{
A() : data(0) {} // Inline function
inline A(A const& copy) : data(copy.data) {}
// Inline function. The keyword inline
// can be used but not necessary.
int data;
};
3 An inline member function (whether static or non-static) may also be defined outside of its class definition provided either its declaration in the class definition or its definition outside of the class definition declares the function as inline. [ Note: Member functions of a class in namespace scope have external linkage. Member functions of a local class (9.8) have no linkage. See 3.5. —end note ]
Example:
class A
{
A(); // Declaration doesn't say whether the function is inline or not.
inline A(A const& copy); // Declaration says the function is inline.
int data;
};
inline A::A() : data(0) {} // Implementation says the function is inline.
inline A(A const& copy) : data(copy.data) {}
4 There shall be at most one definition of a non-inline member function in a program; no diagnostic is required. There may be more than one inline member function definition in a program. See 3.2 and 7.1.2.
Example:
class A
{
A(); // Declaration doesn't say whether the function is inline or not.
inline A(A const& copy); // Declaration says the function is inline.
int data;
};
inline A(A const& copy) : data(copy.data) {}
// Must be defined in a .h file since the declaration says the function is inline.
A::A() : data(0) {} // Non-inline implementation.
// It must be defined in only one translation unit (a .cpp file, not a .h file).

Whether to inline a function or not is entirely up to the compiler's discretion, which means that different compilers might have different criteria for function inlining. That being said, you can prompt the compiler to inline a function with keywords such as inline, __inline, and __forceinline. Still, it does not guarantee that your function will be inlined.
However, there are cases where it's generally impossible to inline. This link from Microsoft would probably give you a good idea about function inlining.
An example of a function that cannot be inlined will be a virtual function. As virtual function calls(i.e. which virtual function definition to call) are determined on run-time, it is impossible for the compiler to figure out which exact function definition will be called at each call of the virtual function.
#include <iostream>
class Base
{
public:
virtual int VirtualFunc();
};
class Derived1 : public Base
{
public:
virtual int VirtualFunc() { return 1; }
};
class Derived2 : public Base
{
public:
virtual int VirtualFunc() { return 2; }
};
int main(void)
{
Base* pBase;
size_t choice;
std::cin >> choice; //Get user input
if(choice == 1) //If user inputs 1, create a Derived1
pBase = new Derived1;
else if(choice == 2) //If user inputs 2, create a Derived2
pBase = new Derived2;
pBase->VirtualFunc(); //At compile-time, no idea if pBase will be Derived1 or Derived2
return 0;
}
Thank you for reading.

Compilation of class methods works same as standalone functions. If you put inline keyword before it, compiler will try to insert it's code to place, where it is called, if it's possible.

Related

Declare, then define a class method - Why an error?

Why doesn't this compile?
class Test
{
void foo();
void foo()
{ }
};
But these will compile:
void bar();
void bar()
{ }
// In same header/file
class Test
{
void foo();
};
void Test::foo()
{ }
The compiler would say that given method cannot be overloaded. The method Test::foo is not being overloaded - it is the same function with exact same signature.
It's explicitly prohibited by the C++ standard. Right there at [class.mfct/1]
A member function may be defined in its class definition, in which
case it is an inline member function, or it may be defined outside of
its class definition if it has already been declared but not defined
in its class definition. A member function definition that appears
outside of the class definition shall appear in a namespace scope
enclosing the class definition. Except for member function definitions
that appear outside of a class definition, and except for explicit
specializations of member functions of class templates and member
function templates ([temp.spec]) appearing outside of the class
definition, a member function shall not be redeclared.
It is just the way it is in C++. Redeclaring a class member is not allowed (unless you consider an out-of-class definition as another declaration). Redeclaring a namespace member is OK as long as you obey ODR.
Why doesn't this compile?
class Test {
void foo();
void foo() { }; // wrong
};
Because, as StoryTeller and others answered, you are declaring and defining the same member function void Test::foo(void) twice (and the inside-class definition of foo is implicitly inline).
If you want to define a member function in your header file after the class, you'll better declare it explicitly as inline like this:
class Test {
inline void foo();
};
and later define that member function (e.g. below in the same header file):
void Test::foo() {
// body of Test::foo
}
BTW, if you declare a member function with outside definition like above, and that member function is not inline but is defined in some header file which is included in several translation units, that function would be multiply defined and the linker would complain.
void foo();
and
void foo() {}
are two ways of declaring functions in a class definition. The first only declares the function and the second declares the function and also implements it. Therefore the compiler assumes that you are going to re-declare the same function and is not a correct overload as the function signature is the same in both.

Why must a method be declared in a C++ class definition?

If only define this method it will have a compiler error.
void classA::testMethod() {
}
And so it must be declared first:
class classA {
void testMethod();
};
Why should these be declared?
I know for common C method methods it is not needed declare, but they can just be defined:
void test() {
}
There are several secondary reasons both objective and subjective (i.e. allows to specify visibility, serves as an interface for the class and probably several others related to compiling and linking phases and TU symbols visibility, not to mention a class is the basic encapsulation unit, with all that implies) but an unquestionable one is that the standard dictates it:
N3797 - class.mfct/p2
A member function may be defined (8.4) in its class definition, in
which case it is an inline member function (7.1.2), or it may be
defined outside of its class definition if it has already been
declared but not defined in its class definition. A member function
definition that appears outside of the class definition shall appear
in a namespace scope enclosing the class definition. Except for member
function definitions that appear outside of a class definition, and
except for explicit specializations of member functions of class
templates and member function templates (14.7) appearing outside of
the class definition, a member function shall not be redeclared.
emphasis mine.
You don't need to declare the method before you define it, but you need to declare class methods in the class. Else it wouldn't be a class method.
That may seem like a contradiction, but a definition is also a declaration. So what this means is that the definition may appear in the class itself:
class A {
void testMethod() { /*...*/ }
};
[edit]
Also, practically speaking, inside the class declaration there are private, protected and public parts. This is needed to for encapsulation. If you could declare methods outside the class, you would lose encapsulation. Anybody could access private members merely by defining extra getters and setters, even when those would not make sense. Class invariants would become meaningless.
It helps encapsulation. If you have a class A
class A {
public:
foo();
bar();
}
You can be sure that only methods foo and bar mess with the private data members of the class. (Or pointer magic or undefined behavior of course)
All of the previous answers are correct as far as they go, but
they fail to point out the reason behind the rule. In C++,
a class definition is closed; you cannot add to it later. This
is necessary for non-static data members, since they determine
the size (and the implicitly generated special functions), but
it is a basic principle in C++ for all class members: not just
data, but functions, types, etc. It is considered essential for
good encapsulation.
This is true for most (but not all) languages which support the
concept of class.
This also explains why it the situation is different for
namespaces (which aren't closed).
Note the use of the qualifier ::. It means
on the left you have a namespace or class identifier
on the right you have a namespace, class, or method / function identifier
So writing void A::testMethod() assumes that there is a class or namespace A defined - this is how C++ is defined. And this applies to
void A::testMethod();
as well as to
void A::testMethod()
{
}
Also note the global namespace where you have indeed nothing at the left of :: as in
void ::testMethod()
{
}
And by definition the global namespace is always defined so the above code defines a function similar to C-style without the qualifier.
Even if it were not mandated by the standard, there are the following two reasons why you need to declare all class methods in the class definition.
You can only declare something as public, private or protected in the class declaration, you can't do so at the method definition in the .cpp file. So what visibility would your free-standing class method have?
If the standard decided to select one of the three as the default (C++ defaults to private), and place that visibility on your method, you now have a scoping problem. Even the most restrictive visibility (private) means that you can use the method in any other member method, including those defined before it in the source file. Without the declaration in the class definition, those earlier functions would not be aware of your free standing method, thus you violate the scoping rules.
In your foo.h header:
class foo
{
public:
foo() {}
virtual ~foo() {}
declaredMethod();
};
In your foo.cpp
foo::declaredMethod()
{
...
freeStandingMethod(); // This should be legal, but it can't work since we
// haven't seen foo::freeStandingMethod() yet
...
}
foo::freeStandingMethod()
{
...
}
Even if you could make this work in the same .cpp file, it's legal to place foo::freeStandingMethod() in a different .cpp file from foo::declaredMethod() at which point this becomes impossible.
This is not an answer, but you might find it informative and fun.
Adding 2 template functions to your class will effectively allow you to call any free function that takes an object of that class as the first parameter:
#include <string>
#include <iostream>
struct puppy {
puppy(std::string name)
: _name(std::move(name))
{}
const std::string& name() const noexcept {
return _name;
}
void set_name(std::string name) {
_name = std::move(name);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args) const
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args)
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
private:
std::string _name;
};
void woof(const puppy& p) {
std::cout << "puppy " << p.name() << " woofs!" << std::endl;
}
void indented_woof(const puppy&p, size_t indent) {
std::cout << std::string(indent, ' ');
woof(p);
}
void complex_woof(const puppy& p, int woofs)
{
std::cout << "attention!" << std::endl;
for (int i = 0 ; i < woofs ; ++i) {
p.perform(indented_woof, 4);
}
}
std::string name_change(puppy& p, std::string(new_name))
{
auto old_name = p.name();
p.set_name(std::move(new_name));
return old_name;
}
int main()
{
puppy fido { "fido" };
fido.perform(woof);
fido.perform(complex_woof, 10);
auto old_name = fido.perform(name_change, "bonzo");
fido.perform(woof);
std::cout << "changed name from " << old_name << std::endl;
return 0;
}
"Methods" or "member functions" (as is the more common terminology in C++) are part of the class declaration. Since you must declare a C++ class in one single place, you must make sure that all "member functions" (or "methods") are already present in that declaration.
I know for common C method methods it is not needed declare, but they
can just be defined
When you refer a "common C method" in C++, you actually mean a "common function". Note that you can declare classes anywhere you can declare such functions.
Also, note that you can declare a member function with a body. You do not have to separate declaration and definition. I.e. this is perfectly valid:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
why should declare these? I know for common c method, there is no need to declare, instead of it just define it:
There is no method in C, just attribute of an struct, wich can be function Pointeur, then associated to a function addresse.
Furthermore you have to declare it in the class definition for the same reason you do it in C:
The compilateur will transform this pre-declaration into a function pointeur then associate to the said methode int the construction of your object.
If a definition of a C++ class should be transformed to a C struct the code would be like this:
struct Aclass {
void (*Amethode))(int);
}
void Amethode(int) { return (0); }
Aclass primaryObject = {&Amethode};
Aclass* AclassConstructor() {
Aclass* object;
object = malloc(sizeof(Aclass));
memcpy(object, primaryObject, sizeof(Aclass));
return (object);
}

Should a virtual c++ method implementation in .cpp file be marked virtual?

I have a virtual C++ method that I'm defining in a .h file and implementing in a .cc file. Should the implementation in the .cc file be marked virtual, or just the declaration in the .h file? E.g., my header has:
virtual std::string toString() const;
The method is implemented in my .cc:
std::string
MyObject::toString() const {
[implementation code]
}
Should the implementation be marked virtual, or is the above code OK? Does it matter?
C++ Standard n3337 § 7.1.2/5 says:
The virtual specifier shall be used only in the initial declaration of
a non-static class member function;
Keyword virtual can be used only inside class definition, when you declare (or define) the method. So... it can be used in implementation file but if it is still in class definition.
Example:
class A {
public:
virtual void f();
};
virtual void A::f() {} // error: ‘virtual’ outside class declaration
// virtual void A::f() {}
int main() {
// your code goes here
return 0;
}
http://ideone.com/eiN7bd
According to the C++ Standard (7.1.2 Function specifiers)
5 The virtual specifier shall be used only in the initial
declaration of a non-static class member function;

C++ class methods forward declaration

Is there any way to redeclare a class to define methods which where only declared this far?
Eg. something like:
class A
{
void a();
void b() {}
}
class A
{
void a() {}
}
instead of
class A
{
void a();
void b() {}
}
A::a() {}
The reason is I created a lot of code with methods defined inside the class defintion, without using headers. I do not had cyclic references up to now, but recently there is need to. I don't like to define bunches of methods by the Type::method syntax, as only very few methods have to be known before the latter definition of the class.
So I like somewhat like a backward declaration, declare or define only a few methods before for cyclic references and define the whole class later.
No, there is no way to redefine a class.
According to the C++ language standard the class definitions is:
class-specifier:
class-head { member-specification_opt }
The standard explicitly says that member specification should be complete within class definition:
Members of a class are data members, member functions (9.3), nested types, and enumerators. The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere.
Also the standard gives example of redefinition of class:
struct S { int a; };
struct S { int a; }; // error, double definition
is ill-formed because it defines S twice.
Unfortunately there is no way to declare the class again once it is Closed with }.
Only thing you can do is you can inherit and define the method.
class B : public A { a() {} } ;

Pure virtual and inline definition

Consider:
struct device{
virtual void switchon() = 0 {}
};
int main()
{
}
I wrote code similar to following and it gave an error:
pure-specifier on function-definition
compilation terminated due to
-Wfatal-errors.
When I asked him, he showed me the following quote from the standard:
A virtual function declared in a class
shall be defined, or declared pure
(10.4) in that class, or both; but no
diagnostic is required (3.2).
I can't seem to understand what it means and I think this somehow is not relevant.
PS: If this is not the relevant quote, please guide me to the proper one so that I can have a better counterargument.
A pure virtual function may have a definition (out of class definition). That is completely optional. But what you are trying to do is plain wrong because
C++03 [Section 10.4/2] says:
[Note: a function declaration cannot provide both a pure-specifier and a definition —end note] [Example:
struct C {
virtual void f() = 0 { }; // Ill-formed
}
However you are free to write
struct device{
virtual void switchon() = 0;
};
void device::switchon() { } // Definition {optional}
int main()
{
}
You can have a "pure" virtual function, i.e. base class has no implementation of the function
virtual void switchon() = 0;
and optionally provide an implementation which derived classes must override.
void base_class::switchon() {}
OR
you can have a "non-pure" virtual function and provide a default or empty implementation
virtual void switchon() {}