As function name had been already declared in header file: function.h and header file were preloaded in OJ, I need to define myAdd in main.cpp, aka OUTSIDE classes. However, most tutorial I can find online about virtual function just define what the function should do INSIDE the class.This is header file:
#ifndef _FUNCTION_H_
#define _FUNCTION_H_
class abstractAdd
{
public:
abstractAdd(){};
~abstractAdd(){};
virtual int myAdd(int a, int b) = 0;
};
class Implement : public abstractAdd
{
private:
public:
Implement();
~Implement();
int myAdd(int a,int b);
};
;
#endif
I have tried this in main.cpp
//include every libraries needed
#include "function.h"
int Implement::myAdd(int a,int b)
{
int c=a+b;
return c;
}
int main(){
abstractAdd& ra = *new Implement();
string input;
while(getline(std::cin, input)){
istringstream testcase(input);
int a,b;
testcase >> a;
testcase >> b;
cout << ra.myAdd(a,b) << endl;
}
return 0;
}
But compiler said:
Undefined symbols for architecture x86_64:
"Implement::Implement()", referenced from:
_main in cc3KANpW.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
How can I implement the function OUTSIDE classes and header files?
new Implement() will create an object. That entails calling the constructor. You declared a constructor Implement();, but didn't define it anywhere.
So the linker is complaining because it can't find the constructor definition.
If you simply wish to use the default constructor as a compiler would define it, you can declare it as follows:
Implement() = default;
It will be defaulted, and defined inline.
Same goes for Implement's destructor as well.
As an aside, while your program is small and probably hosted, it still contains a leak. You allocate with new but don't delete the created object. In real production code, that will be unacceptable. You can simplify your code and rid you self of this concern by using a smart pointer:
std::unique_ptr<abstractAdd> ra = std::make_unique<Implement>();
Now that the object is disposed of correctly when the time comes, you should also make the destructor of abstractAdd virtual as well. Because now you are destroying an object polymorphically.
Related
I'm reading the book "a complete guide to c++". I think there is a typo there on page 252. So I have three files as the following.
In file account.h,
// account.h
// Defining the class Account. class definition (methods prototypes) is usually put in the header file
// ---------------------------------------------------
#ifndef _ACCOUNT_ // if _ACCOUNT_ is not defined
#define _ACCOUNT_
#include <iostream>
#include <string>
using namespace std;
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
bool init( const string&, unsigned long, double);
void display();
};
#endif
// _ACCOUNT_
In file account.cpp,
// account.cpp
// Defines methods init() and display().
// ---------------------------------------------------
#include "account.h" // Class definition
#include <iostream>
#include <iomanip>
using namespace std;
// The method init() copies the given arguments
// into the private members of the class.
bool Account::init(const string& i_name,
unsigned long i_nr,
double i_balance)
{
if( i_name.size() < 1)
return false; // check data format to make sure it is valid
name = i_name;
nr = i_nr;
balance = i_balance;
return true;
}
// the method display() outputs private data.
void Account::display()
{
cout << fixed << setprecision(2)
<< "--------------------------------------\n"
<< "Account holder:" << name << '\n'
<< "Account number:" << nr << '\n'
<< "Account balance:" << balance << '\n'
<< "--------------------------------------\n"
<< endl;
}
And finally, in file account_t.cpp
// account_t.cpp
// Uses objects of class Account.
// ---------------------------------------------------
#include "account.h" // header file which contains class definition; (prototype for member functions)
int main()
{
Account current1, current2; // create two instances with name current1, current2
current1.init("Cheers, Mary", 1234567, -1200.99);
// have to call the init function to initialize a Account object; init function is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
current2 = current1;
current2.display();
current2.init("Jones, Tom", 3512347, 199.40);
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
I do not think it's correct; because obviously there is no way to get access the init member methods and the display member methods, right? I hope this is not a naive question.
EDIT: I tried to run the main function in file account_t.cpp, and got the following output.
~$ g++ account_t.cpp
/tmp/ccSWLo5v.o: In function `main':
account_t.cpp:(.text+0x8c): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0xb6): undefined reference to `Account::display()'
account_t.cpp:(.text+0xd5): undefined reference to `Account::display()'
account_t.cpp:(.text+0x132): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0x15c): undefined reference to `Account::display()'
account_t.cpp:(.text+0x176): undefined reference to `Account::display()'
collect2: error: ld returned 1 exit status
Any more comments are greatly appreciated.
There is no issue with what you are asking about. init and display are declared public in the definition of class Account and the file with the class definition is #includeed properly in the .cpp using these methods.
In order to use a function only its declaration is needed (which is in the class definition in the header which is included). The definition/implementation in the .cpp file is not needed to use the function.
Each .cpp is compiled individually (called a translation unit) and afterwards each use of a function (for which only the declaration might have been available) is linked to the correct definitions from the other translation units if necessary via the function's scope, name and signature. This is called the linking process.
An introductory book to C++ should explain how compilation and linking process work.
For g++, there is an easy way to compile all .cpp files individually as translation units and then directly link them together:
g++ account_t.cpp account.cpp
You always need to add all .cpp to the compiler invocation like that. (There are alternative ways, but this is the easiest one.)
However, as mentioned in the comments there are other issues with this program:
_ACCOUNT_ is a reserved identifier that one may not #define in a program. All identifiers starting with an underscore followed by a capital letter are reserved. Using them causes undefined behavior.
using namespace std; is bad, at the very least when used in a header file, see Why is "using namespace std;" considered bad practice?.
Classes have constructors. One should not write init methods in most cases. The constructor is responsible for constructing and initializing class instances. But no constructor is used in the code.
Money should never be stored in double, because arithmetic with double is imprecise. You should store the value in an integer type in dimensions of the smallest relevant unit of money (e.g. cents).
#include <iostream> is not needed in the header file. One should avoid adding #includes that are not needed.
init returns a boolean indicating successful initialization. But main never checks that value. If a function can fail with an error value, then you must check that error value returned by the function to make sure that continuing the rest of the program is safe.
Some of these points may be excusable as simplification for a beginner program, depending on how far the book got at this point (though 200+ pages should already cover a lot), but others aren't.
Example of constructor use doing the same thing:
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
Account(const string&, unsigned long, double);
void display();
};
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
}
int main()
{
Account current1("Cheers, Mary", 1234567, -1200.99);
// Create Account instance and initialize private members; constructor is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
Account current2 = current1; // Create second Account instance and copy private members from first one
current2.display();
current2 = Account("Jones, Tom", 3512347, 199.40); // Replace instance with a copy of a new one
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
The i_name.size() < 1 check (which is weirdly written, why not i_name.size() == 0?) would be realized by throwing an exception from the constructor:
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
if(i_name.size() == 0) {
throw invalid_argument("Account does not accept empty names!");
}
}
This requires #include<stdexcept> and is a more advanced topic.
I'm aware of using function prototypes, and I was under the impression that forward class declarations could serve a similar purpose when main() and a class are in the same file. For example, I would have expected this would compile:
// main.cpp
#include <iostream>
// class prototypes
class MyClass;
int main(void)
{
MyClass myClass;
// do stuff with myClass here
return(0);
}
class MyClass
{
public:
int someInt;
double someDouble;
// more stuff here . . .
};
But on the MyClass myClass; line I'm getting the error 'myClass' uses undefined class 'MyClass'. What am I doing wrong?
P.S. I'm aware that I could cut/paste main() below all the classes it uses and that would fix the error, but I'd prefer to keep main() as the first function or class.
P.P.S. I'm aware that in any substantial size production program main(), .h content, and .cpp content would be in 3 separate files. In this case I'm attempting to write a small example or test program where main and a class(es) are in the same file.
Forward declarations can only be used via pointers or references.
Calling a constructor function doesn't fall into this category.
I'm aware that I could cut/paste main() below all the classes it uses and that would fix the error, but I'd prefer to keep main() as the first function or class.
That's why usually header files are used, instead of placing all the declarations and definitions in the main.cpp file.
I'm aware that in any substantial size production program main(), .h content, and .cpp content would be in 3 separate files. In this case I'm attempting to write a small example or test program where main and a class(es) are in the same file.
You should still stick to that idiom though, everything else would probably end up in a mess.
This doesn't use forward declarations but it partially addresses the spirit of a single main.cpp with your "main" at the top. I find this technique sometimes useful when you want to share something via an online C++ ide where a single file is much easier to deal with, and you want to focus on the action in main rather than implementation detail in helper structs/classes etc.
#include <iostream>
template<typename MyClass,typename MyOtherClass>
int main_()
{
MyClass a;
a.do_foo();
MyOtherClass b;
b.do_bar();
return 0;
}
struct MyClass
{
void do_foo() { std::cout << "MyClass: do_foo called\n"; }
};
struct MyOtherClass
{
void do_bar() { std::cout << "MyOtherClass: do_bar called\n"; }
};
int main()
{
return main_<MyClass,MyOtherClass>();
}
This question already has an answer here:
linker cannot find a C++ static member [duplicate]
(1 answer)
Closed 6 years ago.
I've declared a public static member to keep the total count of the instances of my class. The code is as follows:
class Hello {
public:
static int myCount;
void test(){
//do nothing
};
Hello(){
Hello::myCount += 1;
};
~Hello() {
Hello::myCount -= 1;
}
};
int main(int argc, const char * argv[]) {
// insert code here...
Hello *p1 = new Hello();p1->test();
Hello *p2 = new Hello();p2->test();
cout << Hello::myCount;
return 0;
}
However, I when compile, it says:
Undefined symbols for architecture x86_64:
"Hello::myCount", referenced from:
_main in main.o
Hello::Hello() in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I don't know where I'm wrong. It's been years from the last time I worked with c++, so could you please suggest a solution?
Thank you.
Static members have to be defined outside of the class, e.g.:
class Hello {
public:
static int myCount;
void test(){
//do nothing
};
Hello(){
Hello::myCount += 1;
};
~Hello() {
Hello::myCount -= 1;
}
};
int Hello::myCount = 0; // definition outside of the class
(...)
Here is an example to show, that it helps to solve your problem: http://ideone.com/LVXVCc
It's all because a rule called One Definition Rule.
You can read more about this one in a context of static class members here.
In short: static int myCount declaration is not a definition of a member. Classes are usually placed in their .h/.hpp header files and are included to many other files. If those'd contain static member and lines like the one above would be a definition, it will lead to the multiple-definitions error.
To prevent that, this declaration is not treated as a definition and you must define it yourself later.
I have a QT library and I want to import it in another project.
Now, since I want that, even when I modify the library, the other project does not need to be compiled again, I started using QLibrary.
But... I can't import a class. Or better, I can import the class, but I can't access its methods.
This is the example I made.
This is the class declaration:
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib
{
public:
TestDLL_lib();
int a;
int b;
int c;
int getValues();
};
and this the implementation:
#include "testdll_lib.h"
TestDLL_lib::TestDLL_lib()
{
a = 10;
b = 20;
c = 30;
}
int TestDLL_lib::getValues()
{
return a+b+c;
}
extern "C" TESTDLL_LIBSHARED_EXPORT TestDLL_lib* create_TestDLL_lib()
{
return new TestDLL_lib();
}
while this is the main file, in the other project:
#include <testdll_lib.h>
#include <QDebug>
#include <QLibrary>
int main(int argc, char *argv[])
{
QLibrary library("TestDLL_lib");
if (library.load())
{
typedef TestDLL_lib* (*create_TestDLL_lib_fun)();
create_TestDLL_lib_fun create_TestDLL_lib = (create_TestDLL_lib_fun)library.resolve("create_TestDLL_lib");
if (create_TestDLL_lib)
{
TestDLL_lib *myClassInstance = create_TestDLL_lib();
if (myClassInstance)
{
//qDebug() << QString::number(myClassInstance->getValues());
qDebug() << QString::number(myClassInstance->a) + " " + QString::number(myClassInstance->b) + " " + QString::number(myClassInstance->c);
}
}
library.unload();
}
}
Now, I can access all the data values (a, b, c) of the object myClassInstance (and, if i change them in the DLL, they also get changed in the program without a rebuild) but I can't call myClassInstance->getValues() because I get
main.obj:-1: error: LNK2001: unresolved external symbol "__declspec(dllimport) public: int __thiscall TestDLL_lib::getValues(void)" (__imp_?getValues#TestDLL_lib##QAEHXZ)
How can I solve this? Is it possible to call methods from imported classes?
Thank you..
You cannot call methods on classes imported at runtime. This is because the compiler links these calls at compile-time and not at run-time (which it cannot do). A way out is provided by our good ol' friend, the vtable:
You can, call virtual methods on classes implementing an interface (the interface is not "imported" at runtime). That means to define a class defining the interface using virtual (possibly pure virtual) methods. TestDLL_lib would then inherit that interface, implementing the methods. You would refer to the TestDLL_lib instance via that interface and call methods trough that interface, effectively calling them trough the vtable of the interface, which is "superseded" by TestDLL_libs vtable.
Don't forget to make your d'tor virtual and to add a virtual dtor to the interface. If you don't do that you cannot safely delete instance trough the interface pointer.
I might also explain why you can access members, but not call functions on "imported" classes. The members are accessed by memory location, and the memory location is solely defined by the compiler. Thus the compiler generates the code to access members without ever referring to any of the classes' symbols (methods and so on). This in turns leads to no linkage dependency. Note however that you would need to recompile both the DLL and the application using the DLL if you change the class, e.g. adding or removing a member, since that changes the memory layout.
class TestInterface
{
public:
virtual ~TestInterface()
{
}
virtual int getValues() = 0;
}
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib : public TestInterface
{
public:
TestDLL_lib();
virtual ~TestDLL_lib();
int a;
int b;
int c;
int getValues() override; // MSVC may not support "override"
};
// return pointer to interface!
// TestDLL_lib can and should be completely hidden from the application
extern "C" TESTDLL_LIBSHARED_EXPORT TestInterface *create_TestDLL_lib()
{
return new TestDLL_lib();
}
class A {
public:
static int i;
static int inc();
};
int A::inc() {
i++;
return i;
}
int main() {
A::inc();
}
As we know that we can access static member variables from static method.
But this code is giving me a error
"A::i", referenced from:
A::inc() in ccn8PKhC.o
ld: symbol(s) not found for architecture x86_64
Can some one please tell me what am i missing
This is a linker error. You've declared the variable, but you haven't defined it, so the linker can't find it.
Add this:
int A::i = 0;
somewhere globally in a .cpp file (outside your class and any function) to define it. If you have multiple .cpp files in your project, the definition needs to be in only one of them.