Why are inline functions allowed to manipulate private member variables? - c++

Suppose I have a class with an two inline functions:
class Class {
public:
void numberFunc();
int getNumber() { return number; }
private:
int number;
};
inline void Class::numberFunc()
{
number = 1937;
}
I instantiate that class and I call both of the functions in the class:
int main() {
Class cls;
cls.numberFunc();
cout << cls.getNumber() << endl;
return 0;
}
I understand that both inline functions are still members of the class, but it is also my understanding that the code within the body of an inline function is just inserted in place of where it was called. It seems that, as a result of that insert, I should not be able to directly access the member variable number because, as far as I know, the code in main() to the compiler would look like:
main() {
Class cls;
cls.number = 1937;
cout << cls.number << endl;
return 0;
}
Can someone explain to me why I am still able to access those private members, or correct me on my understanding of inline functions? I know that compilers have the option to ignore the inline on some functions; is that what is happening here?
Output:
1937

The rules for accessing private members of a class are enforced by the compiler on your C++ code. These rules don't apply directly to the output of the compiler, which is the code that a computer exectues.

The inline keyword does mean that programmer thinks that compiler may if it so wants to insert the code at place of call. Compiler may inline other functions too without the keyword. Compiler may think that programmer is fool and ignore the keyword and not inline. It is all by C++ standard.
The inline member function is otherwise quite normal member function. No other privileges or restrictions.
Inlines do not cause errors that the function is defined by multiple compilation units (that include the header file where the inline function is defined). That may be one reason why people write inline functions.

The private access specifier is a restriction on the users of the class(the programmers), not on the compiler. The compiler can do whatever it wants, as long as the observable behavior of the program is the same.

Related

Does C++ accept inline virtual function while performing polymorphism?

//header.h
#include<iostream>
using namespace std;
struct Base {
virtual void vf();
};
struct Derived :Base {
virtual void vf();
};
inline void Base::vf() {
cout << "Base::vf()" << endl;
}
inline void Derived::vf() {
cout << "Derived::vf()" << endl;
}
//source.cpp
#include"header.h"
int main() {
Base *pb = new Derived;
pb->vf();
}
//source2.cpp
#include"header.h"
It compiles and works in MSVC and g++.
But if I remove both inline keywords, a duplicate definition error will be caught by the linker since I include function definition twice, which will break the ODR.
Since I call the virtual function with a base pointer, it should be decided at run-time, and the compiler will ignore my inlining request, causing the duplicate error.
Do I get something wrong?
As the code is currently written, the member functions are defined in header.h and marked inline. That's okay from the perspective of the language definition: inline means "it's okay to have multiple [identical] definitions of this function". From a maintenance perspective it can make things harder. In particular, when you do this, every time you change the implementation of any of those functions you have to recompile all of the source files that use that header. Putting the definitions of those functions into their own source file[s] means you only have to recompile the file[s] that changed.
If you don't want to mark your functions inline (and you don't want to define them inside the class definition, which makes them implicitly inline), then you have to put each function definition into exactly one source file. A useful first step is to define all of the non-inline member functions of a class in a single source file. So your source2.cpp might look like this (yes, that's member functions from two classes):
#include "header.h"
#include <iostream>
void Base::vf() {
std::cout << "Base::vf()\n";
}
void Derived::vf() {
std::cout << "Derived::vf()\n";
}
and you'd remove those definitions from header.h. So now header.h contains only the class definition; source2.cpp has the definitions of the member functions; and source.cpp has the main function.
The One Definition Rule is mandatory. It is required by C++. A given object or a function must be defined exactly once. Removing the inline keyword (in your case) violates this rule, making the resulting program ill-formed.
Runtime polymorphism and virtual function dispatch happens at run time. You can only get to the run time part if your program is well-formed. If it breaks the ODR it is not well-formed, so how runtime polymorphism and virtual function dispatch works becomes a moot point. If your program is ill-formed there won't be anything to run and no base pointer at all.
It is true that an ODR violation does not require a diagnostic, but the resulting code is still broken. Please write a thank-you note to your compiler for alerting you to the problem.

Inline member do not need declaration

In C++ we have feature people do not think about much, like we can execute method of a class that uses method/member that has been declared later in class i.e.:
struct s{
foo() { foo1();}
foo1() { assert(0); }
};
int main() {
s s1; s1.foo();
}
I already know that compiler puts member definitions after class definition and it can be found so the order doesn't matter: Do class functions/variables have to be declared before being used?. What I was wondering is how it would look like if we would make methods inline and compiler will respect our request and make them really inline would it work then? Would compiler do any additional stuff to reorder whole class?

c++ classes without .cpp file without inline functions?

I already asked a similar question but this one is a bit different
I don't want to write a .cpp file for every simple c++ class.
when I write a class definition and declaration in a single .hpp file, the linker complains about multiple definition of member functions which are not implemented inside the body of the class or defined with inline keyboard.
For example this will work but member functions will become inline :
// log.hpp file
#pragma once
#include<iostream>
class log {
private:
static int m_cnt = 0;
public:
void log();
};
inline void log::log() {
std::cout << ++m_cnt << std::endl;
}
So I use templates to get rid of linker complaints and hope that member functions will not become inline(do they ?):
// log.hpp file
#pragma once
#include<iostream>
template<typename T>
class log_t {
private:
static int m_cnt = 0;
public:
void log();
};
template<typename T>
void log_t<T>::log() {
std::cout << ++m_cnt << std::endl;
}
// some random type (int)
typedef log_t<int> log;
And then I can simply use log class in multiple .cpp files without linker complaints.
even when i use this method will member functions become inline ?
While it is in general bad practice to put everything in a single .h file, there are situations where it's more convenient to do so. Especially when defining small classes, and during prototyping phase where the code can change a lot quickly.
I really don't recommend using templates to solve the linking issue, since it's can slow down compilation and leads to confusion: it's like creating a function taking an argument when you except that argument to always have the same value. Anyway, typing inline is shorter than template<typename T> ;)
So you either have to define your methods in the class body or annotate them with inline if defined out of the body. This is equivalent, since C++ automatically adds inline to methods defined in the class body.
Your concern appears to be with the generated code, you probably wonder if the binary is going to grow too much. But everything's cool since regardless of inline annotations, the compiler looks at every function call and decides whether to inline it or generate a call. This means the same function may sometimes be inlined (if called in a loop) and sometimes be called.
Different compilers have different heuristics, but the inline keyword doesn't have a particularly strong influence on the compiler's decision. You can use things like __forceinline or __attribute__((always_inline)) to make ask more strongly to inline a function, but even then there's no guarantee all calls to the function will be inlined. On the contrary, you may be interested in __attribute__(noinline) for gcc which will (nearly) never inline the call:
inline __attribute__(noinline) void log::log() // gcc
{
std::cout << ++m_cnt << std::endl;
}
If you want to really know what's happening in your code you can use -Winline to see when inline functions are not inlined.
You can also use -Os or -Oz optimization levels to change internal compiler thresholds, so that it will do less inlining.
Related questions which may interest you : here and here.
In general, having every implementation in header files is a BAD idea, since it can lead to very long compile times for larger projects. Using templates to avoid this is not really a good idea, either, since it does not change this fact.
inline is only a hint to the compiler; it may ignore it and inline your template code or not. In short: The answer to your question does not matter. The standard/best way would be to use .cpp files for the implementation, even if you want to avoid it.

C++: Do function wrappers work with inline?

If you've enabled full optimizations in your compiler and have classes setup like this:
class A
{
void Do_A_Stuff();
};
class B
{
A a;
void Do_B_Stuff() { a.Do_A_Stuff(); }
};
class C
{
B b;
void Do_C_Stuff() { b.Do_B_Stuff(); }
};
class D
{
C c;
void Do_D_Stuff() { c.Do_C_Stuff(); }
};
Is there ever a situation where calling Do_D_Stuff() would be slower than directly calling Do_A_Stuff()? Also, would this require the inline keyword on each wrapper 'chain' or, since it is only a suggestion, could the compiler decide to optimize this without the keyword?
I realize there is a lot of information about inlining available, but I could not find any information specifically about chaining many wrappers together.
Also, would this require the inline keyword on each wrapper 'chain' or, since it is only a suggestion, could the compiler decide to optimize this without the keyword?
Yes, the compiler could decide to optimize it anyway, and it could also decide not to optimize it even if you specified the inline keyword (possibly producing a warning if the appropriate compiler options are set) - notice, that member functions defined in a class definition are implicitly marked as inline.
In general, if inlining is possible, the compiler will decide whether to inline or not based on the body of the function being called. However, inlining may not be possible at all if the function is a virtual function, or if the definition of the function is not visible to the compiler.
Provided that the conditions for inlining are satisfied and that the compiler considers it appropriate, there is no technical problem in inlining over a chain of function calls.
As a minor remark, notice that the functions in your classes should be public, otherwise they won't be accessible to your wrappers.
The functions are defined inside the class definition, so the inline keyword is implicit in this case.

Template meta programming inlining

First look at these templates.
struct INIWindows{
inline int GetInteger(){
return 100;
}
};
struct INILinux{
inline int GetInteger(){
return 120;
}
};
template <class Reader>
class SettingsManager : public Reader{
};
Edit: Addendum because it was not clear what i was doing.
int main(){
SettingsManager<INIWindows> Settings;
printf("Integer Reads %i\n",Settings.GetInteger());
system("pause");
return 0;
}
Is my understanding correct that this will result in SettingsManager having an inline function called get integer that will then be inlined properly by the compiler?
Is my understanding correct that this will result in SettingsManager having an inline function called get integer that will then be inlined properly by the compiler.
Yes, your understanding is correct. Your methods are going to be placed in the SettingsManager class, without a virtual dispatch, because the base classes (INIWindows and INILinux) do not have virtual methods.
The inline keyword is only a command for the compiler to try to inline the method - nothing else. It is free not to do it.
inline makes no sense inside a class. If you had defined the functions outside a class then it would indicate internal linkage. But in your current code does not serve any purpose whatsoever: all functions defined in a class are inline.
For the compiler, inline simply means that the name is no visible outside the compilation unit. In this regard, it’s similar to global static. Other than that, the compiler is free to perform function call inlining any way it wants.
In particular, the optimiser may choose to replace a call by the contents of a function. This is what you want, but it’s (almost completely) unrelated to the inline keyword, despite its name.
(By the way, this is unrelated to templates and template metaprogramming.)