Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

(sometimes called a "HAS-A" relationship). For example, a Stack class could inherit privately from a Vector class. Private inheritance bears a much greater similarity to aggregation than to public inheritance.

Protected inheritance is almost never used, and there's no general agreement on what sort of relationship it embodies.

Section 34.5: Friendship

The friend keyword is used to give other classes and functions access to private and protected members of the class, even through they are defined outside the class`s scope.

class Animal{ private:

double weight; double height;

public:

friend void printWeight(Animal animal); friend class AnimalPrinter;

// A common use for a friend function is to overload the operator<< for streaming. friend std::ostream& operator<<(std::ostream& os, Animal animal);

};

void printWeight(Animal animal)

{

std::cout << animal.weight << "\n";

}

class AnimalPrinter

{

public:

void print(const Animal& animal)

{

//Because of the `friend class AnimalPrinter;" declaration, we are

//allowed to access private members here.

std::cout << animal.weight << ", " << animal.height << std::endl;

}

}

std::ostream& operator<<(std::ostream& os, Animal animal)

{

os << "Animal height: " << animal.height << "\n"; return os;

}

int main() {

Animal animal = {10, 5}; printWeight(animal);

AnimalPrinter aPrinter; aPrinter.print(animal);

std::cout << animal;

}

10

10, 5

Animal height: 5

GoalKicker.com – C++ Notes for Professionals

174

Section 34.6: Virtual Inheritance

When using inheritance, you can specify the virtual keyword:

struct A{};

struct B: public virtual A{};

When class B has virtual base A it means that A will reside in most derived class of inheritance tree, and thus that most derived class is also responsible for initializing that virtual base:

struct A

{

int member; A(int param)

{

member = param;

}

};

struct B: virtual A

{

B(): A(5){}

};

struct C: B

{

C(): /*A(88)*/ {}

};

void f()

{

C object; //error since C is not initializing it's indirect virtual base `A`

}

If we un-comment /*A(88)*/ we won't get any error since C is now initializing it's indirect virtual base A.

Also note that when we're creating variable object, most derived class is C, so C is responsible for creating(calling constructor of) A and thus value of A::member is 88, not 5 (as it would be if we were creating object of type B).

It is useful when solving the diamond problem.:

A

A

A

/ \

|

|

B C

B

C

\ /

\ /

D

D

virtual inheritance

normal inheritance

B and C both inherit from A, and D inherits from B and C, so there are 2 instances of A in D! This results in ambiguity when you're accessing member of A through D, as the compiler has no way of knowing from which class do you want to access that member (the one which B inherits, or the one that is inherited byC?).

Virtual inheritance solves this problem: Since virtual base resides only in most derived object, there will be only one instance of A in D.

struct A

{

void foo() {}

GoalKicker.com – C++ Notes for Professionals

175

};

struct B : public /*virtual*/ A {}; struct C : public /*virtual*/ A {};

struct D : public B, public C

{

void bar()

{

foo(); //Error, which foo? B::foo() or C::foo()? - Ambiguous

}

};

Removing the comments resolves the ambiguity.

Section 34.7: Private inheritance: restricting base class interface

Private inheritance is useful when it is required to restrict the public interface of the class:

class A { public:

int move(); int turn();

};

class B : private A { public:

using A::turn;

};

B b;

b.move(); // compile error b.turn(); // OK

This approach e ciently prevents an access to the A public methods by casting to the A pointer or reference:

B b;

A& a = static_cast<A&>(b); // compile error

In the case of public inheritance such casting will provide access to all the A public methods despite on alternative ways to prevent this in derived B, like hiding:

class B : public A { private:

int move();

};

or private using:

class B : public A { private:

using A::move;

};

then for both cases it is possible:

B b;

GoalKicker.com – C++ Notes for Professionals

176

A& a = static_cast<A&>(b); // OK for public inheritance a.move(); // OK

Section 34.8: Accessing class members

To access member variables and member functions of an object of a class, the . operator is used:

struct SomeStruct { int a;

int b;

void foo() {}

};

SomeStruct var;

//Accessing member variable a in var. std::cout << var.a << std::endl;

//Assigning member variable b in var. var.b = 1;

//Calling a member function.

var.foo();

When accessing the members of a class via a pointer, the -> operator is commonly used. Alternatively, the instance can be dereferenced and the . operator used, although this is less common:

struct SomeStruct { int a;

int b;

void foo() {}

};

SomeStruct var;

SomeStruct *p = &var;

//Accessing member variable a in var via pointer. std::cout << p->a << std::endl;

std::cout << (*p).a << std::endl;

//Assigning member variable b in var via pointer. p->b = 1;

(*p).b = 1;

//Calling a member function via a pointer.

p->foo(); (*p).foo();

When accessing static class members, the :: operator is used, but on the name of the class instead of an instance of it. Alternatively, the static member can be accessed from an instance or a pointer to an instance using the . or -> operator, respectively, with the same syntax as accessing non-static members.

struct SomeStruct { int a;

int b;

void foo() {}

static int c; static void bar() {}

};

int SomeStruct::c;

SomeStruct var; SomeStruct* p = &var;

// Assigning static member variable c in struct SomeStruct.

GoalKicker.com – C++ Notes for Professionals

177