Why doesn't C++ allow adding new methods to classes? - c++

It seems like a rather arbitrary limitation.
Aren't regular methods just like C functions with a parameter that points to the instance?
If so I don't see why adding new methods should force me to recompile the rest of my class. Why not allow adding methods via a separate amendment header and a separate amendment implementation.

Consider this example
// in some header
struct X
{
float func(float);
};
// and in another source file
void caller()
{
X x;
std::cout << x.func(2); // will call X:func(float)
}
Now let's say we decide to add a new version of func() that accepts an int.
// in some header
struct X
{
float func(float);
void func(int);
};
// and in another source file
void caller()
{
X x;
std::cout << x.func(2);
}
If the caller() function is not recompiled, there is no way to register that the function it is calling has changed - it will keep calling X::func(float) in the build.
Then - possibly months (or in large systems, years) after the fact - another developer makes a completely unrelated change to one of the functions in the same source file as caller(). Hence that source file gets rebuilt ... finally. Suddenly that person finds that caller() won't compile - with error messages that have nothing whatsoever to do with changes of code he or she is implementing.
All this happens when the offender - the programmer who introduced the new member functions but didn't trigger a recompile and rebuild - is nowhere to be seen.
The developer left behind is left to fix the mess. With no information about what actually caused the problem, why it was working yesterday but not today, no real clue as to how to fix it properly .... but still the one who will be held responsible.
This is just one of many problems that the "arbitrary limitation" in C++ will prevent.

A couple of things comes to my mind. On one hand you need to declare the scope of the method, I presume that's the reason why you are allowed to add new operators in the way that you are suggesting.
On the other hand, you have a problem with inheritance. The compiler need to know all the virtual methods in order to include them in the vtable.

As deviantfan said, it's no real problem really (assuming you want to add a regular (nonvirtual) method).
$ for file in X.hh X.cc X-1.hh X-1.cc main.cc; do echo -e "\n//--------------//$file"; cat "$file"; done
//--------------//X.hh
//X.hh
struct X {
int foo(int);
};
//--------------//X.cc
//X.cc (available as X.o)
#include "X.hh"
int X::foo(int a){ return a+1; }
//--------------//X-1.hh
//X-1.hh
//copy X.hh and amend it
struct X {
int foo(int);
int bar(int);
};
//--------------//X-1.cc
//X-1.cc
#include "X-1.hh"
int X::bar(int a){ return a+2; }
//--------------//main.cc
//main.cc
#include "X-1.hh"
//^the latest definition
#include <iostream>
int main(){
using namespace std;
X x;
cout << x.foo(1) << endl;
cout << x.bar(1) << endl;
And now the building part:
$ make {X,X-1,main}.o
$ g++ {X,X-1,main}.o #links correctly!
$ ./a.out
2
3
Works even if the methods access class/struct variables.
TL;DR:
If you use a build system that uses depend files that track #includes, you can make --assume-old a header (or touch --date='10 minutes ago' changed_header.hh) that only changed by means of trivial method additions (no overloads or virtuals), as all old object files that depended on the old subset of the class's instance methods won't need to be recompiled.
Also, as AliciaBytes points out, there's a proposal for a http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf
that basically allows freestanding functions to be invoked via the dot syntax, so that's basically tantamount to reopening a class for trivial function additions.
Overloaded functions aren't really a problem as you would always #include a particular representation of a class (or the same class + a particular set of dot-syntax mappable free-standing functions) and you could have different versions of the same class (equivalent to having one class + different sets of dot-syntax mappable free-standing functions). (unlike virtual functions, because of vtables and vtable pointers in object instances).

Related

Can you define C++ methods in a reopened class environment, rather than by prefixing with the class name?

In every lesson and book on C++ I've ever seen, a class has been written like this:
header.h
class MyClass
{
...
int myMethod(int my_para);
};
source.cpp
...
int
MyClass::myMethod(int my_para)
{
...
}
But I do find that the MyClass:: just adds to the natural chaos and bewilderment of C++, especially when MyClass is actually more like MySomethingSomethingCreator. I would like to write my class definitions in more of a namespace style, like this:
header.h
class MyClass
{
...
int myMethod(int my_para);
};
source.cpp
class MyClass
{
...
int myMethod(int my_para)
{
...
}
}
Now, I know from trying that doing exactly this does not work, but is there a way to do something similar - just to remove a little of the noise? I am not interested in defining functions actually inside the class declaration - that's the work of the devil!
but is there a way to do something similar
No.
MyClass:: just adds to the natural chaos and bewilderment of C++
It's just one of the little things that a new C++ programmer has to learn to accept. Once you get used to it, it will no longer be bewildering.
MyClass:: just adds to the natural chaos and bewilderment of C++
I wouldn't agree with you. Imagine you are working with a huge code database, and you come across a definition of a function in .cpp file like this.
.
.
.
.
int myfunc(std::string some_arg)
{
//whatever can be here
}
.
.
.
.
.
And now you would wonder, is this a function in a namespace or method of some class. Of course the class specifier you suggested would appear above, but in can be thousand of lines above, or even 10 thousands, which one probably wouldn't want to deal with. Someone would like to know if it is a method or function by directly looking on it.
The MyClass:: specifier serves greatly for this purpose.
You cannot. This is generally not a problem, though. In fact, there is good reason to want to do this with free functions. John Lakos points out in Large-Scale C++ Volume I (2020) p. 155–156, you can (and may want to) do this:
// foo.h
namespace my_product {
int foo(int);
} // namespace my_product
then
// foo.cpp
#include <my_product/foo.h>
int my_product::foo(int x) {
return x * 2;
}
The advantage of this is: suppose you want to change the signature to take float and you change it in the .cpp to float my_product::foo(float x). If done this way, float my_product::foo(float x) can only define the function, it can't declare it, so you'd get a compile error: https://godbolt.org/z/eGbv3rTx5
error: out-of-line definition of 'foo' does not match any declaration in namespace 'my_product'
float my_product::foo(float x) {
^~~
whereas if your .cpp file is
// foo.cpp
#include <my_product/foo.h>
namespace my_product {
float foo(float x) {
return x * 2;
}
} // namespace my_product
and you try to use the function, you have to wait for the whole project to build and then get a link error: https://godbolt.org/z/soo7r97fG
undefined reference to `my_product::foo(int)'
I've started to get in this habit of defining functions like this so I can have immediate compile errors rather than waiting for a potentially big build only to get a link error, which then requires fixing the header (hopefully correctly!) and then waiting again for a big rebuild.

Ensure at compile time that a method is called in exactly one place

I am curious about whether it is possible to ensure at compile time that a method is called in exactly one place.
Note that it is OK if the function is called more than once (e.g. in a loop) - but it should not be called in two separate loops.
This can be broken into two parts, I am also interested in solutions that cover either part:
(a) ensure a method is called in at least one place
(b) ensure a method is called in at most one place
I have full control over the structure of the code, and different idioms that achieve the same idea are welcome.
// class.h
class MyClass {
public:
void my_method();
}
The following should not compile (never called)
#include "class.h"
int main() {
MyClass my_class;
}
The following should not compile (called in more than one place)
#include "class.h"
int main() {
MyClass my_class;
my_class.my_method();
while(true) {
my_class.my_method();
}
}
The following should compile (called in exactly one place):
#include "class.h"
int main() {
MyClass my_class;
while(true) {
my_class.my_method();
}
}
Low Tech Approach:
Since you have control over the code structure (which includes the build system, I assume), here is a low tech solution:
make the function name sufficiently unique
grep for the function name in your code. You are expecting it twice (assuming that you declaration and definition are colocated):
Once in the header
Once at the single call site
Alternatively:
If you really, really, really want to solve it with C++, then you could try
Use a compile time counter to figure out the number of uses within a compilation units
Make sure that the function would violate ODR if the header is included in multiple compilation units.
However, compile time counters are black magic (says I, and I really like TMP), and forcing ODR violations for this purpose seems like similar voodoo (at least you would require a test case that fails to link).
But seriously:
Don't do this. Whatever you do, it can be perverted with almost no effort by a wrapper function:
auto call_my_method(MyClass& o)
{
return o.my_method();
}
MyClass::my_method() is called only in the wrapper. Everybody else just calls the wrapper which is probably even inlined by the compiler.
As others suggested: It might be much more helpful if you would explain what you are trying to do.
Here's a rough idea that may work (too long for a comment - but incomplete for a good SO answer).
You may be able to achieve this by counting/checking template instantiations.
Templates are instantiated only upon use.
Similarly, template method/function bodies are not parsed nor compiled or linked (beyond ensuring valid syntax) if they are never called. This means that any instantiations within their bodies are not made).
You may be able to create a template that maintains some global instantiation count and static assert on that (or some other TMP mechanism to check past instantiations).
There is a partial solution to this question using the C preprocessor and GNU inline assembly:
Header file a.h:
struct A {
// Do not call this method directly, use the macro below to call it
int _method_vUcaJB5NKSD3upQ(int i, int j);
};
// Use inline assembly to ensure that this macro is used at most once
#define method_vUcaJB5NKSD3upQ(args...) \
_method_vUcaJB5NKSD3upQ(args); \
asm (".global once_vUcaJB5NKSD3upQ; once_vUcaJB5NKSD3upQ:");
Implementation file a.cc:
#include <iostream>
#include "a.h"
int A::_method_vUcaJB5NKSD3upQ(int i, int j) { return i+j+5; }
// Ensure that the macro is used at least once
extern "C" const char once_vUcaJB5NKSD3upQ;
static const char get_vUcaJB5NKSD3upQ = once_vUcaJB5NKSD3upQ;
int main() {
A a;
for(int i=0; i<7; i++) {
// Use a separate statement to call the method
// (terminated by a semicolon, it cannot be a sub-expression)
auto x = a.method_vUcaJB5NKSD3upQ(2, 3);
std::cout << x << std::endl;
}
return 0;
}
This solution is partial in the sense that it does not prevent the program to call the method beginning with the underscore directly without using the wrapper macro.
Use a constexpr counter. There is an implementation in another question

Address of a method of an object in C++

As far as I know each created object has its own address, and each object's method also has its own address. I want to verify that with the following idea:
Step 1: Build class A with public method, its name is "method".
Step 2: Create two objects in class A, they are object "b" and object "c".
Step 3: Access the addresses of "b.method" and "c.method" to check that they are equal by using a function pointer.
But I met the problem in step 3 and have found every way to solve but failed.
So I posted up here to ask people to help me how to verify what I said above. Thanks everyone!
And here is my C++ code:
#include<iostream>
using namespace std;
class A
{
public:
int a;
void method()
{
//do something
}
static void (*fptr)();
};
int main()
{
A b, c;
A::fptr= &(b.method); //error: cannot convert 'A::method' from type
// 'void(A::)()' to type 'void (*)()'
cout << A::fptr << endl;
A::fptr= &(c.method); //error: cannot convert 'A::method' from type
//'void(A::)()' to type 'void (*)()'
cout << A::fptr << endl;
return 0;
}
Member functions are not like typical functions. The main difference is the way they are called (they have an implicit this argument), but that difference is enough for the language to demand a new way of defining pointers to them. See here for more details.
The following code prints the address in memory of a method:
#include <iostream>
class A {
public:
void method() {
}
};
int main() {
auto ptr = &A::method;
std::cout << reinterpret_cast<void*>(ptr) << "\n";
return 0;
}
As you can see, I had to cast the pointer to a void* to fool the compiler. G++ prints out a warning on that line, but otherwise does what you want with it.
Notice that the type of ptr is void (A::*)(), i.e. "a pointer to a method in A that receives no arguments and returns void". A pointer to methods in your B and C may be slightly different. They should convert to pointers to A, so you might want to go through that when comparing (or just cast to void* and ignore the warning).
Edited to add:
It seems no cast is needed for comparison. You can just directly compare the two pointers to methods, and they will return true or false correctly.
Thank you everyone!
I've been wondering about this for a long time, and now I've figured out the answer myself, there's only one "method()" that's created on memory, even if there are hundreds of objects created. All objects created that want to use this method will have to find the address of this method. Here is the code to prove what I said:
#include<iostream>
using namespace std;
class A
{
public:
int a;
void method()
{
//do something
}
static void (*fptr)();
};
int main()
{
A b,c;
if(&(b.method)==&(c.method))
{
cout<<"they are same\n";
}
else
{
cout<<"they are not same\n";
}
return 0;
}
The compiler and linker does not have to give distinct functions, distinct implementations.
On at least some platforms, the compiler will spot that 2 functions have the same implementation, and merge the 2 functions into a single piece of code. That limits the amount of bloat added by the template system, but stops it being a guaranteed behavior to identify different member functions.
The compiler can
inline all the examples of a single piece of code, and the result is it doesn't have an address.
share implementations where the code is the same.
create multiple implementations of the same function if it thinks it can be done faster.
When C++ was invented, there was a lot of effort to ensure that a C++ compilation unit was able to call a C compilation unit, and the result of this effort, was that many items of the C++ implementation became visible using compatibility tricks.
The C++ pointer to member function had no backwards-compatibility baggage, and thus no reason to allow it to be inspected. As such it is an opaque item, which can be implemented in multiple ways.
In your example there is only one copy of the method in memory. But i cannot think of any easy way to verify that. You can make thousands of objects and see the memory consumption. You can explore the memory occupied by your object in debugger. The memory consumption may be affected by operating system strategy for assigning memory to process. You can also explore disassembly at https://gcc.godbolt.org/
Relevant start for you would be https://godbolt.org/g/emRYQy

Is it okay to use different implementation files to achieve polymorphism?

In the case where there are multiple desired implementations for a given interface, but where the specific implementation desired is known before compile time, is it wrong simply to direct the make file to different implementation files for the same header?
For example, if have a program defining a car (Car.h)
// Car.h
class Car {
public:
string WhatCarAmI();
}
and at build time we know whether we want it to be a Ferrari or a Fiat, to give each either of the corresponding files:
// Ferrari.cpp
#include "Car.h"
string Car::WhatCarAmI() { return "Ferrari"; }
whilst for the other case (unsurprisingly)
// Fiat.cpp
#include "Car.h"
string Car::WhatCarAmI() { return "Fiat"; }
Now, I am aware that I could make both Fiat and Ferrari derived objects of Car and at runtime pick which I would like to build. Similarly, I could templatize it and make the compiler pick at compile time which to build. However, in this case the two implementations both refer to separate projects which should never intersect.
Given that, is it wrong to do what I propose and simply to select the correct .cpp in the makefile for the given project? What is the best way to do this?
Implementation
As this is static polymorphism, the Curiously Recurring Template Pattern is probably vastly more idiomatic than swapping a cpp file - which seems pretty hacky. CRTP seems to be required if you want to let multiple implementations coexist within one project, while being easy to use with an enforced single-implementation build system. I'd say its well-documented nature and ability to do both (since you never know what you'll need later) give it the edge.
In brief, CRTP looks a little like this:
template<typename T_Derived>
class Car {
public:
std::string getName() const
{
// compile-time cast to derived - trivially inlined
return static_cast<T_Derived const *>(this)->getName();
}
// and same for other functions...
int getResult()
{
return static_cast<T_Derived *>(this)->getResult();
}
void playSoundEffect()
{
static_cast<T_Derived *>(this)->playSoundEffect();
}
};
class Fiat: public Car<Fiat> {
public:
// Shadow the base's function, which calls this:
std::string getName() const
{
return "Fiat";
}
int getResult()
{
// Do cool stuff in your car
return 42;
}
void playSoundEffect()
{
std::cout << "varooooooom" << std::endl;
}
};
(I've previously prefixed derived implementation functions with d_, but I'm not sure this gains anything; in fact, it probably increases ambiguity...)
To understand what's really going on in the CRTP - it's simple once you get it! - there are plenty of guides around. You'll probably find many variations on this, and pick the one you like best.
Compile-time selection of implementation
To get back to the other aspect, if you do want to restrict to one of the implementations at compile-time, then you could use some preprocessor macro(s) to enforce the derived type, e.g.:
g++ -DMY_CAR_TYPE=Fiat
and later
// #include "see_below.hpp"
#include <iostream>
int main(int, char**)
{
Car<MY_CAR_TYPE> myCar;
// Do stuff with your car
std::cout << myCar.getName();
myCar.playSoundEffect();
return myCar.getResult();
}
You could either declare all Car variants in a single header and #include that, or use something like the methods discussed in these threads - Generate include file name in a macro / Dynamic #include based on macro definition - to generate the #include from the same -D macro.
Choosing a .cpp file at compile time is OK and perfectly reasonable... if the ignored .cpp file would not compile. This is one way to choose a platform specific implementation.
But in general - when possible (such as in your trivial example case) - it's better to use templates to achieve static polymorphism. If you need to make a choice at compile time, use a preprocessor macro.
If the two implementations refer to separate projects which should never intersect but still are implementations for a given interface, I would recommend to extract that interface as a separate "project". That way the separate projects are not directly related to each other, even though they both depend on the third project which provides the interface.
In your use case I think it would be best to use ifdef-blocks. This will be checked before compilation! This method is also sometimes used to distinct between different platforms for the same code.
// Car.cpp
#include "Car.h"
#define FERRARI
//#define FIAT
#ifdef FERRARI
string Car::WhatCarAmI() { return "Ferrari"; }
#endif
#ifdef FIAT
string Car::WhatCarAmI() { return "Fiat"; }
#endif
In these code the compiler will ignore the ifdef-block of fiat, because only FERRARI is defined. This way you can still use methods you want to have for both cars. Everything you want different, you can put in ifdefs and simply swap out the defines.
Actually instead of swapping out the defines, you'd leave your code alone and
provide the definitions on the GCC command line using the -D build switch,
depending on what build configuration were selected.

How to parse a function in a cpp file to access the loops

I am working on a C++ project that has gcc as the defined compiler in the makefile. I cannot use a different compiler.
What I need to do is to parse through .cc files which override a particular method called behavior(), inherited from a parent class. This method does not have any arguments and always has void as the return type.
I need to find out the presence of loops (for, while and do-while) within this behavior() method and analyze them in various ways like finding the number of times they are executed etc. For example, let sample.h and sample.cc be the header and source files respectively.
sample.h
class sample_class: public Base
{
....;
....;
void behavior(); //inherited from Base
};
sample.cc
void sample_class::behavior()
{
....;
....;
int n=10;
int count=0;
int c=2;
for(int x=0;x<n;x++)
{
count=count+n; //LOOP1
}
while(int z<5)
{
c=c*5; //LOOP2
}
}
What I want to do is to access the contents of for and while and be able to write something like:
exec_time(behavior)=n*exec_time(LOOP1)+5*exec_time(LOOP2)
Could someone please guide me as to how I can do this while using GCC as the compiler?
Thank you very much for any help.
"finding the number of times they are executed" - this (and only this) requirement necessarily requires runtime counting... you could either modify the relevant functions so they count how often they're called and save the call stack each time, then do some analysis on that output, or try using a profiling tool that already captures the same kind of information - perhaps gprof, or even Quantify or valgrind.