3.6 オブジェクトポインター
3.6.1 アロー演算子
#include <iostream>
class A{
public:
void foo();
};
void A::foo(){
std::cout << "A::foo()" << std::endl;
}
void call_foo(A* pa){
pa->foo();
}
int main(){
A a;
call_foo(&a);
}
3.6.2 thisポインター
thisポインターは、そのメンバー関数呼び出しに使われたオブジェクトを指し示すポインターが格納されている。
#include <iostream>
class A{
int value;
public:
void set_value(int value);
int get_value() const;
};
// 仮引数かメンバー変数か曖昧なときは、thisポインターを使う。
void A::set_value(int value){
this->value = value;
}
int A::get_value() const{
return this->value;
}
int main(){
A a;
a.set_value(2);
std::cout << a.get_value() << std::endl;
}
3.6.3 thisポインターは変更不可能
3.6.4 constメンバー関数とthisポインター
constメンバー関数の中ではthisポインターはconstポインター。(thisポインターの指すオブジェクトを変更することができない。)
#include <iostream>
class A{
int value;
public:
void set_value(int value);
int get_value() const;
int get_value2() const;
};
void A::set_value(int value){
this->value = value;
}
int A::get_value() const{
return this->value;
}
int A::get_value2() const{
した二つがエラーになる。thisポインターはconst A*になってるから、変更できないし、constじゃない関数も呼ぶことができない。
// this->value = 0;
// this->set_value(2);
return this->get_value();
}
int main(){
A a;
a.set_value(2);
std::cout << a.get_value() << std::endl;
}
3.7 クラス、構造体、共用体の関係性
3.7.1 クラスと構造体の違い
違いはデフォルトのアクセス指定子。
クラスはprivate、構造体はpublic.
#include <iostream>
class Base
{
int value = 0;
public:
void set_value(int value);
int get_value() const;
};
void Base::set_value(int value)
{
this->value = value;
}
int Base::get_value() const
{
return value;
}
// 構造体がクラスから派生することもできる。
struct Derived:Base
{
Derived();
~Derived();
};
Derived::Derived()
{
std::cout << "constructor" << std::endl;
}
Derived::~Derived(){
std::cout << "destructor" << std::endl;
}
int main(){
Derived d;
std::cout << d.get_value() << std::endl;
}
3.7.2 共用体とクラスの違い
共用体→全てのメンバー変数が同じメモリアドレス上に置かれる点が異なる。
#include <iostream>
union U{
float f;
private:
int i;
public:
U();
int get_i() const;
};
U::U(): i(0xdeadbeef){
std::cout << "&f " << &f << std::endl << "&i " << &i << std::endl;
}
int U::get_i() const {
return this->i;
}
int main(){
U u;
std::cout << std::hex << u.get_i() << std::endl;
u.f = 2.71828f;
std::cout << std::hex << u.get_i() << std::endl;
}
&f 0x16efff288
&i 0x16efff288
deadbeef
402df84d
3.7.3 無名共用体
共用体のインスタンスを作らないまでも、いくつかの変数が同じメモリ上に配置されているということだけ指定したい。
#include <iostream>
class A{
union{
int i;
float f;
};
long l;
public:
A();
int get_i() const;
void set_f(float f);
long get_l() const;
};
A::A() : i(0xdeadbeef), l(0xc0ffee){
std::cout << "&f " << &f << std::endl;
std::cout << "&i " << &i << std::endl;
std::cout << "&l " << &l << std::endl;
}
int A::get_i() const{
return i;
}
void A::set_f(float f){
this->f = f;
}
long A::get_l() const{
return l;
}
int main(){
A a;
std::cout << "i " << std::hex << a.get_i() << std::endl;
a.set_f(2.71828f);
std::cout << "i " << std::hex << a.get_i() << std::endl;
std::cout << "l " << std::hex << a.get_l() << std::endl;
}
&f 0x16b0cf280
&i 0x16b0cf280
&l 0x16b0cf288
i deadbeef
i 402df84d
l c0ffee
無名共用体となっているメンバー変数は、同じアドレス値になっている。
無名共用体をグローバル変数で使うには、staticを指定する必要がある。
3.8 フレンド関数の概要
フレンド関数: メンバー関数でないにも関わらず非公開メンバーにアクセスすることができる関数。
3.8.1 フレンド関数の宣言方法
#include <iostream>
class vector3d{
float x;
float y;
float z;
public:
vector3d();
explicit vector3d(float x, float y, float z);
// プロトタイプ宣言にfriendをつけただけ
friend vector3d add(const vector3d& lhs, const vector3d &rhs);
void dump() const;
};
vector3d::vector3d(): vector3d(0,0,0){};
vector3d::vector3d(float x, float y, float z): x(x), y(y), z(z){};
vector3d add(const vector3d& lhs, const vector3d &rhs){
vector3d result;
result.x = lhs.x + rhs.x;
result.y = lhs.y + rhs.y;
result.z = lhs.z + rhs.z;
return result;
}
void vector3d::dump() const{
std::cout << x << "," << y << "," << z << std::endl;
}
int main(){
vector3d a(1,1,1), b(1,2,3);
// メンバー関数じゃないから普通の関数と同じ呼び方をする。しかし非公開メンバーにアクセスすることができる。
vector3d c = add(a,b);
c.dump();
}
フレンド宣言はクラスの外側では行うことができない。
3.9 staticクラスメンバー
3.9.1 staticクラスメンバーとは
特定のインスタンスと結びつかないメンバー変数やメンバー関数のこと。
staticメンバー変数は、main()前に初期化されるから、グローバル変数と同じように初期化される。
#include <iostream>
class S{
public:
static int num;
};
int S::num = 123;
int main(){
std::cout << S::num << std::endl;
S::num = 456;
S s;
std::cout << s.num << std::endl;
}
コンストラクタないで初期化することができない。どこか別のところで定義する必要がある。
特定のインスタンスと紐づくわけではないので、constメンバー関数からでも変更できる。
- staticメンバー変数のカプセル化
#include <iostream>
class S{
static int count;
public:
S();
~S();
void show_count();
};
int S::count = 0;
S::S(){
++count;
}
S::~S(){
--count;
}
void S::show_count() {
std::cout << "S::count" << count << std::endl;
}
void function(){
S a;
a.show_count();
}
int main(){
S a;
a.show_count();
function();
a.show_count();
}
S::count1
S::count2
S::count1
3.9.2 staticメンバー関数
#include <iostream>
class S{
static int count;
public:
S();
~S();
// staticメンバー関数の宣言。これはconstとすることはできない。
static void show_count();
};
int S::count = 0;
S::S(){
++count;
}
S::~S(){
--count;
}
void S::show_count() {
std::cout << "S::count" << count << std::endl;
}
void function(){
S a;
a.show_count();
}
int main(){
S::show_count();
S a;
a.show_count(); //インスタンスから呼び出すこともできる
}
章末
#include <iostream>
class Shape
{
int area;
public:
static int v;
virtual void calArea() = 0;
int getArea() const;
void setArea(int a);
};
int Shape::v = 2;
int Shape::getArea() const{
Shape::v = 8;
return area;
}
void Shape::setArea(int a){
area = a;
}
class Rectangle : public Shape
{
int height = 0;
int width = 0;
public:
Rectangle(int height, int width);
void calArea() override;
using Shape::setArea;
void setArea();
};
Rectangle::Rectangle(int height, int width) : height(height), width(width)
{
}
void Rectangle::calArea()
{
setArea(height*width);
}
void Rectangle::setArea(){
std::cout << "名前の隠蔽" << std::endl;
}
int main(){
Rectangle rec(2,3);
rec.calArea();
std::cout << rec.getArea() << std::endl;
// static変数は派生クラスからでも呼び出すことができる
std::cout << rec.v << std::endl;
rec.setArea();
}