Let's say I make an abstract class with some pure virtual functions and derive 2 classes off of it. From my understanding the pure virtual functions are there in the abstract class as placeholders for the derived classes to sort-of fill in. However, when I go to compile the code without providing a function body for the one in the abstract class I get a Linker error. But when I do define the function for the abstract class it works. Why?
I thought that the whole point of pure virtual functions was to avoid the need of defining them in the base class. Am I mis-understanding some subtle point on virtual and pure virtual methods?
The point of pure virtual functions is to prevent instances of the abstract class. The functions themselves may have bodies (and if they are pure virtual destructors, they must have bodies).
@Cubbi - other than virtual destructors, I thought other pure virtual functions did not have to have a body defined in the abstract class, but when I don't define the body for the function in the abstract class I get a linker error.
@Mathhead - Yes, except I would get an error for the PureAbstract method, because it doesn't have a body (which it shouldn't need, correct?).
The error I get is an LNK2019 error, in visual studio 2010. I'm not sure how much that helps though.
class PureAbstract {
public:
virtualvoid method() = 0;
};
class Derived : public PureAbstract {
public:
virtualvoid method() { PureAbstract::method(); }
};
int main() {
Derived d; //this line causes a LNK2019 error in visual studios for me
}
Hmm..I don't think I am. Like what I've done is create a PureAbstract pointer that points to an array. Then I made parts of the array AbstractDerived1 and other parts AbstractDerived2 (all are derived objects) and invoke the methods after that. All the elements are initialized by the time I use the array to access objects' methods and such. So it shouldn't be invoking the PureAbstract.
Okay, I think I see why it wouldn't work now. I had scanned over the code a bit too quickly and missed a function call for a function that hadn't been defined. This code runs, I'm still going to post it and would appreciate validation of the first couple comments I made in the definition files. Thank you for all the help.
//method definitions
// acctabc.cpp -- bank account class methods
#include <iostream>
#include <cstring>
using std::cout;
using std::ios_base;
using std::endl;
#include "acctabc.h"
// Abstract Base Class
AcctABC::AcctABC(constchar *s, long an, double bal)
{ // Constructor is still needed with
//abstract class.
std::strncpy(fullName, s, MAX - 1);
fullName[MAX - 1] = '\0';
acctNum = an;
balance = bal;
}
void AcctABC::Deposit(double amt)
{
if (amt < 0) //The comment below applies to this function to.
cout << "Negative deposit not allowed; "
<< "deposit is cancelled.\n";
else
balance += amt;
}
void AcctABC::Withdraw(double amt)
{
balance -= amt; /* from what I understand, the only reason that this
is used often. But this definition is not necessary as
long as the functions that need it are re-done.right?*/
}
// protected method
ios_base::fmtflags AcctABC::SetFormat() const
{
// set up ###.## format
ios_base::fmtflags initialState =
cout.setf(ios_base::fixed, ios_base::floatfield);
cout.setf(ios_base::showpoint);
cout.precision(2);
return initialState;
}
// Brass methods
void Brass::Withdraw(double amt)
{
if (amt < 0)
cout << "Withdrawal amount must be positive; "
<< "withdrawal cancelled.\n";
elseif (amt <= Balance())
AcctABC::Withdraw(amt); // This is the function call I missed
else
cout << "Withdrawal amount of $" << amt
<< " exceeds your balance.\n"
<< "Withdrawal cancelled.\n";
}
void Brass::ViewAcct() const
{
ios_base::fmtflags initialState = SetFormat();
cout << "Brass Client: " << FullName() << endl;
cout << "Account Number: " << AcctNum() << endl;
// rest is edited out to save screen space on post...all functions do get defined though.