Simple typo:
if (r=y && c==x){
should be:
if (r == y && c == x){
(notice the double = signs.
**Please use code-tags in the future.
Simple typo:
if (r=y && c==x){
should be:
if (r == y && c == x){
(notice the double = signs.
**Please use code-tags in the future.
It works anywhere, but it _should_ not be used in a header file. The motivation is essentially that you don't want it to have repercussions on the code that includes that header file (i.e. the user of the header file might not want to import the std namespace, so you should never do it in a header file). So, the guideline is that if you want to use "using namespace std;" in your code, you have to restrict it only to cpp files, and thus, in the header files, you have to use the full qualifications like "std::string" or "std::cout".
First of all, this thread should answer all your questions about what a DLL is and what is meant by "dynamic-link".
Now, for a simple example of a DLL, here is the simplest example I can think of, the "hello world" program:
In hello_world.h:
#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
#ifdef COMPILING_DLL
#define DLL_FUNCTION extern "C" __declspec(dllexport)
#else
#define DLL_FUNCTION extern "C" __declspec(dllimport)
#endif
DLL_FUNCTION void printHelloWorld();
#endif
In hello_world.cpp:
#define COMPILING_DLL
#include "hello_world.h"
#include <iostream>
DLL_FUNCTION void printHelloWorld() {
std::cout << "Hello World!" << std::endl;
};
In main.cpp:
#include "hello_world.h"
int main() {
printHelloWorld();
return 0;
};
Now, you must compile the "hello_world.cpp" as a DLL and then compile the "main.cpp" as an executable, linking it with the import library of the DLL.
If you are using MinGW GCC, then you can do this:
g++ hello_world.cpp -shared -o hello_world.dll --out-implib libhello_world.a
g++ main.c -o main.exe -lhello_world
If you are using MSVC, then you should just create one "DLL" project with the "hello_world.cpp" file as the source file. And then, create one executable project with the main.cpp file. You need to first compile the DLL project (as "hello_world.dll"), then add the "hello_world.lib" to your link-libraries in your executable's project settings (build options), and then compile the executable. Or, equivalently in command-line:
cl -o hello_world.dll hello_world.cpp /link /DLL
cl -o main.exe main.cpp hello_world.lib
I'm pretty sure the above will work.
The Boost.MPL is a great tool for template meta-programming. It basically contains an entire compile-time implementation of the STL containers and algorithms. So, yes, there are plenty of alternatives to loki::Typelist. In MPL terms, these are Sequences. You can choose, like with STL containers, whether you want random-access or not, associative container or not, sorted or not, etc. It goes quite a bit beyond the Typelist implementation.
If you are reading Alexandrescu's book, the important thing is to learn the tricks of the trade, in template meta-programming. For actual feature-rich implementations and code that you can use, you should look towards Boost, the Boost.MPL in particular, and, of course, David Abraham's book on template meta-programming which, besides being a really good book on TMP, is almost an instruction manual to using the Boost.MPL.
>>care to expand?
I tend to think of data hiding as a likely consequence of encapsulation. In a similar sense that encapsulation is the bundling of data and behaviour in a single entity, I usually also attach to that the presence of some form of hiding the details (like the stuff that is done under-the-hood to preserve the class invariants). This is different from abstraction, in my book.
Abstraction is to define, like in the example given, what a dictionary object should do. While encapsulation is to bundle all the things necessary to get that done.
Now, it doesn't mean that you have to hide the information that is bundled in your class, in fact it doesn't require that you hide anything. But, in general, you will expose whatever is necessary for the object to fulfill its abstract purpose and its concrete purpose, and hide everything else. So, information hiding is usually a part of the process of encapsulation, but not strictly necessary (although highly recommended, of course).
Also, may I remind you that information hiding takes two forms, hiding data and hiding functionality (or behaviour). Sometimes you do one, sometimes the other, and sometimes both, depending on the problem.
You can simply store your objects in a vector, that is, you can do:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class record
{
public:
string name;
string bankAccountNum;
double accountBalance;
void output();
};
int main()
{
//create a vector container of customers:
vector<record> customers;
record customer;
//set the members of one customer.
customer.name = "David R. Sanders";
customer.bankAccountNum = "324235634";
customer.accountBalance = 12392.23;
customers.push_back(customer); //add the customer to the vector.
//set the members of another customer.
customer.name = "John Doe";
customer.bankAccountNum = "89745243";
customer.accountBalance = 24542.67;
customers.push_back(customer); //add the customer to the vector.
//iterator through the customers and print out their info:
for(int i = 0; i < customers.size(); ++i) {
cout << customer[i].name << endl;
cout << customer[i].bankAccountNum << endl;
cout << customer[i].accountBalance << endl;
customer[i].output();
};
system("pause");
return (0);
}
>>what do you call it now that it is tied to a shared library such as a DLL?
The .lib / .a file that makes the link to the DLL is called an "import library", and it is indeed a static library (albeit a special kind of static library). It is just a static library that contains an amount of code to import the DLL at load-time, in other words, it acts as the "middle-man" between your code and the dynamic library.
>>is it only the DLL/so itself that is called dynamic?
Yes. Except that .so files are not usually called dynamic libraries, they are either called with the general term "shared library" or with specific term "shared object file". DLLs and shared-objects are actually very different because the dynamic linking models used by Windows and *nix systems are very different, and in fact, in *nix systems you don't need an "import library" to link to an .so file (but in MinGW in windows, you need a .a file to use a DLL).
First, the obvious, in both cases, you have compiled code, so it is all a matter of linking and loading.
In all cases, a .lib file is a static-link library, meaning that it is used by the linker to complete all the function calls that exist in your application that refer to functions in that library. At the end, the linker grabs all the compiled code from the library (only the functions that are actually called at some point) plus all the compiled code from your program, and bundles everything into an executable file. So, we call it statically linked because all the links between function call-sites and the blocks of compiled code for those functions are accomplished before the final executable is created.
Now, when you actually run an executable, the operating system has to do a number of things, of which I won't mention too many details. Basically, the OS has to "load" the executable, giving it a chunk of memory to work with and a virtual address space to address that memory. Then, the executable itself runs a certain amount of code to initialize itself as well, and then the "main" function starts executing.
In many ways, a DLL is conceptually more closely related to an executable than it is to static library. A DLL, like an executable, has to be loaded by the operating system which gives it a place to live in the system's memory, and allows it to run some initialization …
I don't understand where the lambda-expression would come into play. If you mean replacing the functor with a lambda-expression that could accept different parameter types, then you can't really do that because lambda-expressions cannot be templated, because lambda-expressions are expressions, they don't declare a type. They actually evaluate to a temporary callable object of a unnamed class type, in other words, creating a lambda expression is analogous to this (if you neglect the fact that lambdas are temporary and you neglect the practical problem with using local classes as functors):
int main() {
std::vector<int> v;
//fill v with values.
//sort with a lambda-expression:
std::sort(v.begin(), v.end(), [](int a, int b) -> bool { return a < b; });
//or, create a local functor object:
struct {
bool operator()(int a, int b) { return a < b; };
} foo;
//sort with that local functor (note, this is not actually legal in C++):
std::sort(v.begin(), v.end(), foo);
return 0;
};
The problem is although you could give "foo" templated / overloaded call operators to allow for different parameters (although you would need to bring it outside the function). You cannot do the same with the lambda-expression because it was designed to directly translate to the above analogy, without the possibility of providing multiple alternative overloads. I don't know if that was ever debated or considered as a possible addition to lambda-expressions, but considering that lambdas are mostly syntactic sugar, it would seem like complexifying its syntax to allow for more complex use-cases …
Just do like I said, overload the call operator in your functor:
struct difference_set
{
bool operator()( A const &Fir, B const &Sec) const
{
return Fir.num_one < Sec.num_two;
}
bool operator()( B const &Fir, A const &Sec) const
{
return Fir.num_two < Sec.num_one;
}
};
Usually, I don't like template template parameters, because of the weirdness associated with them (both in implementing the class template that receives the parameter as well as in using it). I usually prefer to go the route of meta-factory types instead.
Consider this meta-factory:
template <typename FactoryTag, typename T, typename U>
struct binary_functor {
BOOST_STATIC_ASSERT(false,"General binary_functor template is invalid!");
};
Then, if you want to create, say, a less-than functor, you could simply do this:
template <typename T, typename U>
struct less_than : public std::binary_function<T,U,bool> {
bool operator()(const T& a, const U& b) const {
return a < b;
};
};
//first create a meta-factory tag:
struct less_than_tag { };
//and then, specialize the meta-factory for that tag:
template <typename T, typename U>
struct binary_functor< less_than_tag, T, U> {
typedef less_than<T,U> type;
};
And now, your template-param-swap thing can be implemented as:
template<typename U, typename T, typename FunctorTag>
struct template_param_swap
{
typename binary_functor<FunctorTag, U, T>::type func1; #1
typename binary_functor<FunctorTag, T, U>::type fun2; #2
};
The syntax is not necessarily much nicer, but the above is a solution that tends to scale much better and be able to tailor more easily to different situations via either partial specializations of the meta-factory or different ways in which to compute the functor types.
Why not use a functor with a template call-operator. That's the way I usually take care of this kind of problem. You can also use overloading rules (and even Sfinae) if you want different implementations for different pairs of types. Here is what I mean:
struct difference_set
{
template <typename T, typename U>
bool operator()( T const &Fir, U const &Sec) const
{
return Fir.num < Sec.num;
}
};
Then you can just call set_difference_if (the original implementation) like this:
set_difference_if(A.begin(), A.end(), B.begin(), B.end(), std::back_inserter(C), difference_set() );
What's wrong with that? If you need two behaviours for different type pairs, then just make various overloads (or Sfinae-switched template overloads) of the operator() in your functor class. It's as easy as that.
Post the updated code.
Well, the "unhandled exception" is due to the fact that the function pointer obtained from the "GetProcAddress" is NULL, i.e., it is not found in the DLL. You should check for the pointer being NULL and I'm sure it will confirm that.
I didn't initially understand that you generated the DLL with Cygwin (Linux environment), I'm not very familiar with it. Certainly, if your DLL was generated like that, you cannot load it from an MSVC program, at least, not easily. As said, they are not compatible.
Your DLL has to be compiled with a native Windows compiler (not a *nix compiler wrapped in an emulated environment like Cygwin). MinGW should work for that. To install it, you can either simply install CodeBlocks (with mingw) which will do the install of MinGW automatically, or you can install it manually (which means to unzip the latest release of MinGW to some folder, and then add the path "C:\Path\to\MinGW\bin" to the PATH environment variable in Windows).
@vijayan121:
>>If it were so, libstdc++.so or libboost_thread.so would be examples of fundamental programming errors. As in everything else, what is required is that the library and the program using the library have to be ABI compatible.
Comparing *nix shared-objects with Windows DLLs is comparing apples and oranges, they are completely different in almost every way (linking model, dynamic loading model, ABI specification, memory model, etc.). They just look …
Move the while(true) {
line to line 11. That should display the menu again every time.
Just replace the lines 21 and 22 with these two lines:
while(true) {
cin >> Option;
The rest can remain the same, for now.
Well, facebook is a social network, which has the word network in it, which usually implies a graph structure. And, coincidently enough, facebook uses a graph structure at its core, how surprising... I didn't need to look far to find that out, look at the wiki or the developers' page.
>>Aren't those contradictionary statements?
Ok, let me restate that more clearly. If all the functions you need are exported already from the DLL, then you can use it without any major issues, but you will need to load it at run-time (e.g. with LoadLibrary) if you don't have an import library for it.
My first statement was more in response to vijayan's assessment about ABI being an issue here, which I don't think it is. But, of course, with or without ABI issues, you certainly need the required functions to be exported from the DLL, otherwise it is not usable in any context. My first statement was thus starting from the assumption that the DLL has functions exported from it, and my second statement was in response to the OP's vague statement that the DLL was "without exports", which certainly entails a recompilation in order to export the required functions.
>>My question is, can I use this DLL now without recompiling my C code to incorporate the DEF file?
Yes, as far as I know, it shouldn't be a problem. (btw, I know that I am contradicting vijayan121 on this, he may be right, but I think not, I think he is being a bit over-cautious, ABI shouldn't be a problem here)
Because your DLL is entirely written and compiled in C, binary compatibility should not be an issue. Of course, if your C code uses fixed-size integer type (like uint8_t and such) then you need your C++ code to use the same types, and be sure that they correspond (in endian-ness for example). The calling convention is easy to determine, if there is no special specification of the calling convention in the C source, then it is "__cdecl" which is also the default in C++ (but you're better off specifying it explicitly). Binary footprints and alignment for types and structs in C are essentially fixed (given that the OS and target platform is the same for both compilations). Name decoration is not done in C. And if you have exceptions propagating across the module boundary (an exception thrown in the DLL propagating into the application code), then that is an error regardless of what languages or compilers or settings or whatever, exceptions should never be allowed to propagate across a module boundary (that's a fundamental rule when programming DLLs). Now, if your DLL is actually …
>>the proof of a stupid programmer
Are you suggesting I'm a "stupid programmer"? Not only is that disrespectful and uncalled for, but I can assure that you are wrong (and pretty presumptuous too).
>>a loop is infinite if the parameters make it so regardless of the code inside
What "parameters"? I guess you mean the conditional statements that usually appear either while( /* here */ ) { }
, for(; /* here */ ;) { }
or do { } while( /* here */ );
. Then, first of all, that code is _inside_ the loop, you can check the C++ standard document if you don't trust me (section 6.5.1/2, in n3242). Second, by your logic, which of these are infinite loops:
//A)
while(true) {
break;
};
//B)
for(int i = 0; i < 10; ++i) {
--i;
};
//C)
foo:
{
std::cout << "bar" << std::endl;
goto foo;
}
According to your logic: A) is an infinite loop, B) is not an infinite loop, and C) is not a loop at all.
However, ask any programmer who is worth that title and he/she will tell you that B) and C) are infinite loops and that A) is not. You know, a question like the above could easily be in an exam for an introductory course in programming, this is fundamental stuff (programming 101), it isn't up for debate.
>>It is still a lung, but the bullet has stopped it. it is still an infinite loop. just stopped by return 1;
I think that you put too much "philosophy" into it. An infinite loop is just a loop that runs forever, and so, your loop is not an infinite loop. When you put philosophy into it, you could conclude that all loops are infinite, or you could conclude that no loop is infinite, or you could conclude that there is no such thing as a loop. That's a problem I always had with philosophy, it sometimes asks most irrelevant questions and provides the most useless answers. Programming is about posing concrete problems and finding practical answers. Programming and philosophy don't mix very well.
Food for thoughts, here's another philoso-gramming question: what's the value of a variable that's set but never used?
On most distros you should be able to just use the "alarm" character (0x07, or "\a" as an escaped sequence). In other words, this should work:
#include <iostream>
int main() {
std::cout << "\a";
return 0;
};
If not, you can use the "beep" program (install it with "sudo apt-get install beep", and check the manual).
But, before you try too many things, verify that you have a PC Speaker and that it is enabled, use the command amixer scontents
and you should see an entry called "PC Speaker" and its playback should be enabled (i.e. Linux distros often disable the PC speaker after startup).
>>What is cout? It's a variable, yet it can print stuff on the screen. std::cout
is an object of the class std::ostream
(or a class derived from std::ostream
). It has an internal connection to the terminal output (or DOS output), which is the same as the C alternative stdout
. Most systems implement the terminal input/output by a kind of file emulation, this is why the type of stdout
is FILE*
. The std::cout
object also does buffering of the data that is outputted to it, for maximum efficiency in the memory access.
>>Also, << (Left Shift Operator) isn't like the one for the variable cout.
The basic semantics of the left-shift operator is to perform a binary bit-shift to the left. However, C++ allows for operator overloading for any user-defined class. This means that you can define your own function(s) to be called when a certain operator is used. In general, this feature is used to be able to create a custom class that can behave as a built-in type (with the same operators) and this usually implies that the semantics of the operators are preserved (a + sign is an addition, etc.). The developers of the C++ standard I/O library thought it would be a good idea to use the left-shift and right-shift operators to do input / output operations, this is ok because the original semantics of these operators is clearly not applicable in this case (you can't do a left bit-shift on an …
>> Is it really hard to find someone who know how to make a good use of stl
I would say that people who can't make good use of STL are not really "hire-material" for any kind of job where C++ programming skill is a key asset. Using the STL, and to some extent Boost, is pretty main-stream today. Using STL containers, making some use of STL algorithms, being familiar with smart-pointers, and so on, are pretty basic skills today in C++ programming. I would say that someone who lacks that has sub-par proficiency in C++.
>> and combined the power of GP and OOP?
Those who are only proficient in plain OOP (i.e. Java-like OOP skills) are functional but seriously handicapped in C++. It is also important to note that even though people might not be proficient at harvesting the power of GP in their own design (i.e. making GP functions or classes), it doesn't mean they not able to use GP libraries (like the STL or Boost). You can easily teach a beginner to use std::vector
or std::sort
or boost::shared_ptr
, even though they have no idea of how to make similar stuff, let alone the design methodology involved in doing that. Someone who can comfortably use GP techniques and design methodologies is a person I would qualify as an "advanced" or "expert" C++ programmer (depending on the level of sophistication).
>> Like the way modern c++ design did?
Remember that Alexandrescu's book …
Like Fbody said.
Line 8 should be:
node<T>* link;
Line 16 should be:
node<T>* start;
Line 18 should be taken out.
Line 21 should be:
start=NULL;
Line 29 should be:
void ll<T>::add()
Line 32 should be:
node<T>* temp = new node<T>;
Line 42 should be:
node<T>* ptr;
>>like make those unproper inline function become non-inline
Inline functions are not a problem. In general, small functions should be inline (e.g. set/get functions, empty constructors, etc.). Inlining is a very important optimization, and non-inlining just for the benefit of not having any function definitions inside a class declaration is an unnecessary pessimization of the code. Just thought I would point that out.
I agree totally with your "rant" on commenting the code. The habit of writing comments on the interfaces of code (i.e. in doxygen style) is one of the top qualities I consider a programmer can have.
I find that one good way to motivate people to use documentation is to generate a doxygen documentation from the code, with the option to "hide undocumented members". Then build a culture of referring to that doxygen document (usually nightly built on the source code server) instead of digging through the actual source code when looking for functions to use and stuff. This way, developers are strongly encouraged to document their "usable" code well such that others can find it in the documentation instead of always coming to him/her with questions or misusing his/her code.
>>Don't act different else you will become a jerk
This is not a problem of what you do, it is a problem of how you do it. You shouldn't position yourself as the "guy who knows better" or the "evil code scrutinizer" or whatever. Be humble. Just …
I'm not a great expert in business concerns in software developments, so take my opinion for what it is worth.
It does seem that your company has been camping itself strongly on the side of "lets get the software done asap", as opposed to "lets build a robust and sustainable software project going". Personally, I balance more towards the latter. General software development experience has taught people that neither extremes are practical. If you "just get the software running", you usually carry a large handicap for future development in the form of poor abstractions, ill-defined interfaces, un-resolved silent bugs, etc. If you "make a master-piece of software engineering", you might never see the end of it, but at the same time, your development cycle is a lot more predictable (e.g. if you always do rigorous unit-tests, you never get surprised by a horrible bug that requires a lot of programming to fix and causes delays that weren't planned for).
In other words, the former approach allows you to plan for a shorter development cycle, but you also have to plan for a lot of contingency, and you might spend more time in contingency recovery than on actual development. While the latter approach will certainly increase the length of your development cycle, but the time you have to plan for contingencies is small. It all depends on which approach leads to the smallest sum (developing + fixing). The main problem with the "real-world" is that many people (especially in …
These operators can easily be computed from the other operators:
if( a NAND b)
// is equivalent to:
if( ! (a && b) )
And so on for other operators. The C/C++ designers didn't see the point in having all operators, just the basic ones.
The error is due to the fact that you cannot add-and-assign to a temporary value. In this case, the value returned by the getSavingsBalance is a temporary value (formally called an "rvalue"). Because the return value is a double, you could simply do:
cout << (SaverFour.getSavingsBalance() + 1000.00) ;
Or, if you wish to use your operator += overload, you need to apply it to the SaverFour object itself, as so:
cout << (SaverFour += 1000.0);
// or, to just print the amount:
cout << (SaverFour += 1000.0).getSavingsBalance();
You left semi-columns at the end of your definition prototypes, remove them:
SavingsAccount& SavingsAccount::operator -=(double increase) //notice no ';' here.
{
SavingsBalance -= decrease;
return *this;
}
Your other errors are due to the lines at the end of your main function that look like this:
cout << SaverFour.getSavingsBalance() += 1000.00;
The problem here is that the compiler evaluates the << operator first and then tries to evaluate the +=, resulting in trying to add-store 1000.0 in the ostream object, which is not possible. You solve this problem with a simple set of parentheses:
cout << ( SaverFour.getSavingsBalance() += 1000.00 ) ;
Your prototypes for operator overloads do not match. In your declaration, you have:
SavingsAccount& operator+=(const SavingsAccount& );
In your definition, you have:
SavingsAccount& SavingsAccount::operator+=(const SavingsAccount& double increase);
Which is not correct syntax by the way. Either the type is 'double' or it is 'const SavingsAccount&', you have to choose. Personally, I don't see how it could make sense to add two SavingsAccount together, so I guess you intended to use "double" all along, so you should do so:
SavingsAccount& operator+=(double );
//and:
SavingsAccount& SavingsAccount::operator +=(double increase);
Ok. Now that you are almost there, I'll complete it.
Basically, the first two lines in your loop are almost correct. The other two lines should be taken out. This would give you this loop:
//Statement
while(n > 0)
{
sum += n % 10; //notice '+=' here, which adds 'n % 10' to 'sum'.
n = n / 10;
}
Your are jumping the guns here. I laid out three steps to do, you jumped over the second step, which is screwing up your last step.
So, to recap, what you need to do is this:
1) Ask the user for a number, and store that number in an integer variable.
--> This is done in your lines 6, 7 and 8.
2) Iterate through the digits of the number. In the iteration you should first print out each digit to make sure your loop is working correctly. Then, you should sum up the digits.
--> You skipped this step. This is the only step that must be done in a loop.
3) Check if the sum of digits is divisible by 3 and/or 9.
--> You did this inside a loop, which doesn't make sense, this test only needs to occur once, once you have the sum of digits.
So, starting from your code, you can make the skeleton of your program by simply separating the three steps clearly:
#include <iostream>
using namespace std;
int main()
{
// 1) Prompt the user for a number:
int n;
cout << "Write down random numbers from 0-9 and I will add them together." << endl;
cin >> n;
// 2) Iterate through the digits to sum them up (print also for debugging):
int sum = 0; //the sum starts at 0.
while(n > 0)
{
//Here is the only piece …
>>Where does the integer k come in?
Forget about the integer k, it is not relevant. Just go about steps I described in my previous post. Don't forget to compile and run your code very often, and play with it. You're doing good so far, keep going, step by step.
Go incrementally.
Start by learning Basic Input/Output in C++.
Then, try to print all the digits of an input number (as an int
). To extract the digits, you are going to need a while-loop and the second hint given to you (about 425175 % 10 = 5 and 425175 / 10 = 42517).
Finally, once you can print the digits, you can easily sum them up and use your first hint to test if that sum is divisible by 3 and/or 9.
First, your function definitions must always match your prototypes exactly. This means that you should have this definition of the functiony() function:
//Calling y which I call k and d is x;
double functiony(double d)
{
return d*d*d;
}
Then, if you need to use the functiony() function in your integration function, then you should simply do so, you need to call the functiony function within your integration function to compute k. Also, on a side note, to make the code clearer and safer, you should declare variables where you use them first, not all at the beginning of the function. So, your integration function could be like this:
//Intergration f is number of rectangles, g is x1 and h is x2, d is x.
double area(int f, double g, double h)
{
double step = (g-h)/f;
double sum = 0;
double d = g; //the 'd' value should start at x1 (g)
for (int i=1;i<=f;i++)
{
double k = functiony(d); //call the functiony function to get 'k' at value 'd'.
double area = k * step;
sum += area;
d += step;
}
return sum;
}
That's it.
Given the way the Fibonacci sequence works (by adding the last two values) you can pretty safely use the double type, results will not be exact (floating-point operations never are), but the range will go up to really large values (about 1.8 x 10^308).
Also, the int
and long
types are the same in most implementations. You'll have better luck with the uint64_t
type from the <stdint.h> header. But that type will only go up to 2^64 (about 1.845 x 10^19). I think some platforms even provide uint128_t
.
For higher integer numbers, you will have to use variable length integer types, which only come from special libraries, such as BigInt.
>>When reading a book written by Microsoft
I didn't realize that "Microsoft" could write a book, that puts "corporations are people" in a whole new perspective.
Certainly, you need to learn about programming in general, not just COM. I don't think you can use COM if you don't know how to program. Anyways, the question is about the advantages of using COM versus not doing so (with just a simple DLL).
>>all of the debugs where the same size and all the releases are the same size.
As I said, most of the size of those binaries are probably due to a fixed amount of basic code that the compiler puts in for the C/C++ standard libraries. The part that is compiled from your code is probably very small in comparison. Compilers probably also do a certain amount of padding (inserting blank memory to better align the different parts of the code) and your code probably doesn't exceed that padding, and thus, you get the exact same size every time.
Well. My best guess to explain the difference in size is that C++ has constructs that are a lot more feature-rich than their C counter-parts. Taking a simple "Hello World" program example, in C it will just involve using the printf()
function, while the C++ version would entail constructing the std::cout
object and a lot of its underlying code (iostream code has several levels of classes and buffers). So, basically, basic features of the standard library in C++ would just amount to quite a bit more code than the C counterparts. This is not so relevant because it will not grow with the size of your code (it is like a starting size). But, of course, C++ code will tend to create larger binaries (and the -Os
can certainly help to reduce that if it is really a concern), by how much is a question I cannot answer (it also depends highly on your coding style).
As for compiler-vendors and how they compare in sizes of binaries, I can't tell specifically, but GCC is amongst the best compilers all-around, it is only beaten by the Intel compilers (ICC) but these are quite expensive (thousands of dollars).
Exporting classes from a DLL cannot really be done reliably because of binary compatibility issues (different compilers, compiler versions, and compilation options can produce (slightly) different binary foot-prints for the objects of a given class). The COM is (amongst other things) a strict specification of how the binary foot-print should look like for a given COM class. This solves the binary compatibility problem. Also, COM provides means to query an unknown class for its interface, so you can import classes that are not known. There are ways to achieve the same effect without using COM and simply using DLLs, but that can easily get to be fairly complicated.
The compiler is GCC (for all Linux distros).
With Ubuntu, you can simply run this in the terminal:
$ sudo apt-get install build-essential
(the dollar sign is just to represent the start of the command prompt in the terminal, you shouldn't type it)
The "build-essential" package will install GCC (for C, C++ at least) and all relevant tools (like "make").
GCC is obviously just a command-line compiler. It is not an IDE like Visual Studio, or Dev C++, that's a separate thing, i.e., Visual Studio is an IDE that uses the Microsoft compiler (or MSVC for short), and Dev C++ is an IDE that uses the GCC port for Windows (with MinGW).
With GCC installed, you can compile a simple C++ program by going to its directory (via the terminal) and typing this (for "foo.cpp" for example):
$ g++ -Wall foo.cpp -o foo
And that's it.
Now, if you want an IDE to work with, then you have quite a few to choose from. Some Linux purists would say that "emacs" is the only thing you need (just an enhanced text-editor, with syntax highlighting and stuff). More reasonably, I could recommend three that seem prevalent, Qt Creator (package: "qtcreator"), CodeBlocks (package: "codeblocks") or KDevelop (package: "kdevelop"). They can all be installed from apt-get or through your synaptic (or package manager).
Then it is a problem with either your default constructor for the CDROM class or with the loadInfo() or displayInfo() functions. Post the relevant code (i.e. those three functions at least), and we can look into it.
The problem is that you don't initialize your pointers to point to anything. You have to do the same as you do for (pCDROM1, pCDROM2, pCDROM3) pointers but for each pCDs element. As in:
for (int i = 0; i < 3; i++)
{
pCDs[i] = new CDROM;
if (pCDs[i] == NULL)
{
cout << "Dynamic Memory Allocation FAILED" << endl;
}
}
Your problem is the factor PI/270.0
which you use to transform degrees into radians. It is wrong, to convert degrees into radians, you need to use the factor PI/180.0
. This explains why your arc is only 2/3 of the angular sweep that it should have (i.e. 120 degrees instead of 180 degrees).
Also, note that lines like glRotatef(60.0, 0, 0, 0);
are completely useless. The glRotate function works by giving an angle (in radians, btw) and then the three components of the axis of rotation around which to perform the rotation (that's the last three numbers). If all the last three values are zero, then you won't get any rotation at all. So, lines like these have no effect at all.
Learn to use indentation (and space-out your code) and please write in correct English (i.e. "Do post in full-sentence English" it is really annoying to read things like "it z bt hr n dr i v prbs plz hlp" instead of "It's between here and there that I have problems, please help me.").
What do you mean by graphics?
If you mean a graphical user interface, I suggest you take a look at Qt.
If you mean 3D graphics rendering, I suggest you take a look at OpenGL, NeHe tutorials are a great place to start (although out-dated a bit).
And if you actually mean doing both, then look at QGLWidget (part of Qt, allows you to embed an OpenGL view-port inside a GUI).
Assuming that you are using the wizard program (i.e. the GUI program, not the command-line one), then you will find the useful sections for configuration under the "input" and "preprocessor" tabs of the Expert configuration wizard.
Under "Input" you can configure the directories and files to include (INPUT), the file patterns (file extensions to include), the files or directories to exclude, the file patterns to exclude, the symbols to exclude (e.g. I often configure to exclude then entire "detail" namespace, in which case, I just add the keyword "detail" to the EXCLUDE_SYMBOLS field), and other stuff.
Under "Preprocessor", you can control the pre-processing done. Of course, because doxygen is not a compiler, it doesn't automatically define symbols such as __cplusplus
, so, you need to explicitly provide those definitions. First, you obviously need to tick the "ENABLE_PREPROCESSING" check-box. Second, you can either list the predefined symbols you need to enable those conditionally compiled pieces of code (you do so under the "PREDEFINED" field), or you can put all those #defines in a header file (that isn't included by any parts of the real code, and is also excluded from the doxygen input) and then add that header file folder to the "INCLUDE_PATH" such that doxygen will pre-process it and thus define all the predefined symbols that you need.
Finally, to control the things that are documented and not, you will find those under the "Build" tab where you can tick all the options you like. Typically, I …
You need the magic of Perfect Forwarding in order to completely avoid the unnecessary copies. If you use the C++11 versions of the bind() functions (in header <functional>
), you get much better performance.
First, I tried your code (with Boost.Bind):
test_for_bind tb_0;
boost::bind( &test_for_bind::tamaya1, test_for_bind() )();
boost::bind( &test_for_bind::tamaya1, boost::ref(tb_0) )();
test_for_bind_00 tfb00_0;
boost::bind( &test_for_bind::tamaya2, &tb_0, boost::cref(tfb00_0) )();
boost::bind( &test_for_bind::tamaya2, boost::ref(tb_0), boost::cref(tfb00_0) )();
F2 f;
boost::bind(f)();
Which gave me this output:
this is copy constructor :: tamaya
this is copy constructor :: tamaya
this is copy constructor :: tamaya
this is copy constructor :: tamaya
tamaya
tamaya
this is copy :: tamaya
this is copy :: tamaya
this is copy :: F2
this is copy :: F2
this is copy :: F2
F2, F2, F2
Which means that only the test_for_bind() and the f temporaries are copied several times, everything else is forwarded correctly. I don't why your implementation copies the const-ref parameter ( tfb00_0
), it shouldn't. My boost version is 1.45.0
Now, if I use the C++0x version (with GCC 4.6.2), I tried this exact replica:
test_for_bind tb_0;
std::bind( &test_for_bind::tamaya1, test_for_bind() )();
//boost::bind( &test_for_bind::tamaya, tb_0 )();
std::bind( &test_for_bind::tamaya1, std::ref(tb_0) )();
test_for_bind_00 tfb00_0;
std::bind( &test_for_bind::tamaya2, &tb_0, std::cref(tfb00_0) )();
std::bind( &test_for_bind::tamaya2, std::ref(tb_0), std::cref(tfb00_0) )();
F2 f;
boost::bind(f)();
And I got this output:
this is copy constructor :: tamaya
tamaya
tamaya
this is copy :: tamaya
this is copy :: tamaya
this is copy :: F2
this is copy :: F2
this is …
It's the analog of:
void test(some_type* const & A)
So, yes, it is perfectly fine.