Taking your PDF examples as starting point, let's look at this.
http://en.wikipedia.org/wiki/Single_responsibility_principle
The Single Responsibility Principle suggests that an object should have one and only one objective. Keep this in mind.
http://en.wikipedia.org/wiki/Separation_of_concerns
Separation of Concerns principle tells us that classes should not have overlapping functions.
When you look at these two, they suggest that logic should go in a class only if it makes sense, only if that class is responsible for doing that.
Now, in your PDF example, the question is, who is responsible for printing? What makes sense?
First code snippet:
Pdf pdf = new Pdf();
pdf.Print();
This is not good. A PDF document does not print itself. It gets printed by... ta da!.. a printer. So you second code snippet is much better:
Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);
This makes sense. A Pdf Printer prints a pdf document. Better yet, a printer shouldn't be a PDF printer, or a photo printer. It should just be a printer capable to print stuff sent to it to the best of its capabilities.
Pdf pdf = new Pdf();
Printer printer = new Printer();
printer.Print(pdf);
So that's simple. Put methods where they make sense. Obviously, it is not always that simple. Take your country statistics for example:
Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();
Your concern is that there might be n number of statistics, and that they shouldn't be in a Country class. That is true. However, if your model only calls for that particular statistics, this modeling example might actually be fine.
In this case, you could say quite logically that a country should be able to compute its own statistics, specific to your model and the requirements at hand.
And therein lies the thing: what are your requirements? Your requirements will drive the way you model the world, the context, in which these requirements are to be satisfied.
If you indeed have a multitude/variable number of statistics, then your second example makes more sense:
Country m = new Country("Mexico");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(m);
Better yet, have an abstract superclass or interface called Statistics that take a country as parameter:
interface StatisticsCalculator // or a pure abstract class if doing C++
{
double getStatistics(Country country); // or a pure virtual function if in C++
}
class DebtToGDPRatioStatisticsCalculator implements StatisticsCalculator ....
class InfantMortalityStatisticsCalculator implements StatisticsCalculator ...
And so on and so on. Which leads to the following: generalization, delegation, abstraction. Statistical gathering gets delegated to specific instances that generalize a specific abstraction (a statistics collection API).
I don't know if this answers your question 100%. After all, we don't have infallible models ground on inviolable laws (like EE folks do.) All you can do is put things were they make sense. And that's an engineering decision you need to make. The best thing to do is to really get acquainted with OO principles (and good software modeling principles in general.)