Programming Language & Its Applications β C++ Constructs with Objects and Classes, NEC licence examination syllabus (Nepal Engineering Council).
Inside the class or outside it with :: β the choice affects inlining, compile times, and how your codebase is organised.
.so with the definitions, and your compiler needs nothing more. Search "C++ compilation model translation unit" to see the whole picture β it explains a surprising amount of C++'s oddities.#include <iostream>
#include <string>
#include <cmath>
class Triangle {
double a, b, c;
public:
/* defined inside β short, implicitly inline */
Triangle(double x, double y, double z) : a(x), b(y), c(z) {}
double perimeter() const { return a + b + c; }
bool valid() const { return a+b>c && b+c>a && a+c>b; }
/* declared here, defined below β substantial bodies */
double area() const;
std::string classify() const;
void describe() const;
};
double Triangle::area() const {
if (!valid()) return 0.0;
double s = perimeter() / 2.0; /* Heron */
return std::sqrt(s * (s-a) * (s-b) * (s-c));
}
std::string Triangle::classify() const {
if (!valid()) return "invalid";
if (a == b && b == c) return "equilateral";
if (a == b || b == c || a == c) return "isosceles";
return "scalene";
}
void Triangle::describe() const {
std::cout << a << ", " << b << ", " << c
<< " " << classify()
<< " perim=" << perimeter()
<< " area=" << area() << "\n";
}
int main() {
Triangle t1(3, 4, 5);
Triangle t2(5, 5, 5);
Triangle t3(2, 2, 3);
Triangle t4(1, 2, 9); /* impossible */
t1.describe(); t2.describe(); t3.describe(); t4.describe();
return 0;
}
Output:
3, 4, 5 scalene perim=12 area=6
5, 5, 5 equilateral perim=15 area=10.8253
2, 2, 3 isosceles perim=7 area=1.98431
1, 2, 9 invalid perim=12 area=0
this pointer#include <iostream>
class Widget {
int id;
public:
Widget(int i) : id(i) {}
void whoAmI() const {
std::cout << "id " << id
<< " (this = " << this << ")\n";
}
/* these two lines are identical */
int get1() const { return id; }
int get2() const { return this->id; }
/* disambiguating a parameter that shadows a member */
void setId(int id) { this->id = id; }
};
int main() {
Widget a(1), b(2);
a.whoAmI(); b.whoAmI();
std::cout << "&a = " << &a << " &b = " << &b << "\n";
b.setId(99);
std::cout << "b.get1()=" << b.get1()
<< " b.get2()=" << b.get2() << "\n";
std::cout << "sizeof(Widget) = " << sizeof(Widget)
<< " (just the int β methods add nothing)\n";
return 0;
}
Output:
id 1 (this = 0x7ffd1a2b3410)
id 2 (this = 0x7ffd1a2b3414)
&a = 0x7ffd1a2b3410 &b = 0x7ffd1a2b3414
b.get1()=99 b.get2()=99
sizeof(Widget) = 4 (just the int β methods add nothing)
Notice this printed inside whoAmI equals &a printed outside β same object, same address. And sizeof(Widget) is 4 despite four member functions, because the code lives once in the text segment, not per object.
#include <iostream>
class Counter {
int count = 0;
mutable int reads = 0; /* changeable in const fns */
public:
void increment() { ++count; } /* non-const */
int get() const { ++reads; return count; }
int readCount() const { return reads; }
};
void observe(const Counter &c) {
/* c is const here, so only const members are callable */
std::cout << "observed " << c.get() << "\n";
/* c.increment(); <-- compile error */
}
int main() {
Counter c;
c.increment(); c.increment(); c.increment();
observe(c); observe(c);
std::cout << "value " << c.get()
<< ", read " << c.readCount() << " times\n";
return 0;
}
Output:
observed 3
observed 3
value 3, read 3 times
Const-correctness is worth taking seriously because it propagates. One non-const getter forces every caller that holds a const Counter& to give up, so they take a non-const reference, so their callers do too. Retrofitting const into a large codebase is famously painful for exactly this reason β it is cheap to add up front and expensive to add later.
#include <iostream>
/* single-file version of the split above */
class Stack {
int data[5];
int top;
public:
Stack();
bool push(int v);
bool pop(int &out);
bool empty() const { return top == -1; }
bool full() const { return top == 4; }
int size() const { return top + 1; }
};
Stack::Stack() : top(-1) {}
bool Stack::push(int v) {
if (full()) return false;
data[++top] = v;
return true;
}
bool Stack::pop(int &out) {
if (empty()) return false;
out = data[top--];
return true;
}
int main() {
Stack s;
for (int i = 10; i <= 70; i += 10)
std::cout << "push " << i << ": "
<< (s.push(i) ? "ok" : "FULL")
<< " size=" << s.size() << "\n";
int v;
std::cout << "popping: ";
while (s.pop(v)) std::cout << v << " ";
std::cout << "\nempty now: " << std::boolalpha
<< s.empty() << "\n";
return 0;
}
Output:
push 10: ok size=1
push 20: ok size=2
push 30: ok size=3
push 40: ok size=4
push 50: ok size=5
push 60: FULL size=5
push 70: FULL size=5
popping: 50 40 30 20 10
empty now: true
The pops come out reversed β 50 40 30 20 10 β because a stack is LIFO. Note out = data[top--] reads the element and then decrements, which is the postfix-versus-prefix distinction from the pointer topic doing real work here.
#include with a compiled interface, and they can cut build times by a large factor. Search "pimpl idiom compile firewall" and "C++20 modules vs headers"; both are things a good project would actually use.ClassName:: and that the inside form is implicitly inline. Explain the this pointer as the hidden first parameter and use it to justify why methods do not increase sizeof and why static functions cannot access non-static members. const member functions are frequently asked β state what they forbid and that only they are callable on a const object.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦